Merge pull request #3866 from lehni/fix/colour-glyph-cache-key

Type: colour glyphs keep each fill's own colour, also between colours that look alike
This commit is contained in:
BFlat
2026-10-24 04:10:30 +07:00
committed by GitHub
3 changed files with 31 additions and 3 deletions
+10
View File
@@ -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;
+3 -3
View File
@@ -425,8 +425,8 @@ type GlyphImages = GlyphCache<(u32, u32), Arc<GlyphImage>>;
/// [`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<TextColours>), 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))) {
+18
View File
@@ -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);