diff --git a/crates/color/src/lib.rs b/crates/color/src/lib.rs index 9af14253d..5de064d6b 100644 --- a/crates/color/src/lib.rs +++ b/crates/color/src/lib.rs @@ -111,6 +111,16 @@ impl Color { pub fn out_of_gamut(&self) -> bool { cms::active().out_of_gamut(self) } + /// The colour exactly, as a key: its model and its components' bits (colours that only look + /// alike, as a grey and the same RGB grey, differ). + pub fn key(&self) -> [u32; 5] { + match *self { + Color::Rgb { r, g, b } => [0, r.to_bits(), g.to_bits(), b.to_bits(), 0], + Color::Cmyk { c, m, y, k } => [1, c.to_bits(), m.to_bits(), y.to_bits(), k.to_bits()], + Color::Gray { k } => [2, k.to_bits(), 0, 0, 0], + Color::Lab { l, a, b } => [3, l.to_bits(), a.to_bits(), b.to_bits(), 0], + } + } pub fn to_rgba8(&self, alpha: f32) -> [u8; 4] { let [r, g, b] = self.to_rgb(); let q = |v: f32| (v.clamp(0.0, 1.0) * 255.0).round() as u8; diff --git a/crates/text/src/fontdb.rs b/crates/text/src/fontdb.rs index a459e0491..a1b232bc4 100644 --- a/crates/text/src/fontdb.rs +++ b/crates/text/src/fontdb.rs @@ -425,8 +425,8 @@ type GlyphImages = GlyphCache<(u32, u32), Arc>; /// [`FontDb::glyph_colour`]'s answers by face and glyph, and the text's fill and stroke colours for /// glyphs that paint with them. type GlyphColours = GlyphCache<(u32, u32, Option), ColourContent>; -/// The text's fill and stroke colours, as a cache key. -type TextColours = ([u8; 4], Option<[u8; 4]>); +/// The text's fill and stroke colours, as a cache key ([`Color::key`]). +type TextColours = ([u32; 5], Option<[u32; 5]>); /// What a glyph's colour content (an image, layers) takes of memory, in bytes. trait Weight { @@ -2573,7 +2573,7 @@ impl FontDb { let svg = svg_drawn(face, &f, gid); // Kept without colours, or by the text's colours it uses: the fill, and for SVG art the // stroke too. - let coloured = Some((foreground.to_rgba8(1.0), stroke.filter(|_| svg).map(|c| c.to_rgba8(1.0)))); + let coloured = Some((foreground.key(), stroke.filter(|_| svg).map(|c| c.key()))); { let cache = self.colours.lock().unwrap_or_else(|e| e.into_inner()); if let Some(c) = [None, coloured].iter().find_map(|k| cache.kept.get(&(face.id, gid, *k))) { diff --git a/crates/text/src/tests_colr.rs b/crates/text/src/tests_colr.rs index 6f1ad40a6..116eeff3c 100644 --- a/crates/text/src/tests_colr.rs +++ b/crates/text/src/tests_colr.rs @@ -189,6 +189,24 @@ fn the_foreground_layer_takes_the_runs_fill_and_black_for_a_gradient_fill() { assert_eq!(foreground(gradient), Paint::solid(Color::BLACK)); } +/// Fills that look alike but separate differently (a grey on the black plate, the same RGB grey on +/// all four) each paint the foreground layer in their own colour. +#[test] +fn fills_that_only_look_alike_each_paint_the_foreground_layer() { + let db = colr_db(false); + let foreground = |fill: Color| { + let st = CharStyle { fill: Paint::solid(fill), ..colr_style(false) }; + let l = layout(&db, &TextObject::point(KPoint::ZERO, &COLOUR_CHAR.to_string(), st)); + let colour = l.glyphs[0].colour.clone().unwrap(); + children(&colour)[1].appearance.fill_paint() + }; + let grey = Color::gray(0.5); + let rgb = Color::rgb8(128, 128, 128); + assert_eq!(grey.to_rgba8(1.0), rgb.to_rgba8(1.0), "they look alike"); + assert_eq!(foreground(grey), Paint::solid(grey)); + assert_eq!(foreground(rgb), Paint::solid(rgb)); +} + #[test] fn layout_bounds_take_in_the_colour_layers() { let db = colr_db(true);