.
diff --git a/glifo/src/colr.rs b/glifo/src/colr.rs index 0c67c6a..40d3c35 100644 --- a/glifo/src/colr.rs +++ b/glifo/src/colr.rs
@@ -6,18 +6,22 @@ use crate::atlas::commands::AtlasPaint; use crate::color::Srgb; use crate::color::{AlphaColor, DynamicColor}; -use crate::glyph::{GlyphColr, OutlinePath}; +use crate::glyph::{ + CachedOutline, FontEmbolden, FontInfo, GlyphColr, OutlineCacheSession, OutlinePath, + VarLookupKey, +}; use crate::interface::DrawSink; use crate::kurbo::{Affine, Point, Rect, Shape}; use crate::peniko::{self, BlendMode, ColorStops, Compose, Extend, Gradient, Mix}; use crate::util::FloatExt; +use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; use core::fmt::Debug; use peniko::{LinearGradientPosition, RadialGradientPosition, SweepGradientPosition}; use skrifa::color::{Brush, ColorPainter, ColorStop, CompositeMode, Transform}; use skrifa::instance::LocationRef; -use skrifa::outline::{DrawSettings, OutlineGlyphCollection, pen::ControlBoundsPen}; +use skrifa::outline::OutlineGlyphCollection; use skrifa::raw::TableProvider; use skrifa::raw::types::BoundingBox; use skrifa::{FontRef, GlyphId, MetadataProvider}; @@ -41,10 +45,11 @@ impl<T: DrawSink + ?Sized> ColrDrawSinkExt for T {} /// An abstraction for painting COLR glyphs. -pub(crate) struct ColrPainter<'a> { +pub(crate) struct ColrPainter<'a, 'b> { transforms: Vec<Affine>, colr_glyph: &'a GlyphColr<'a>, outline_glyphs: OutlineGlyphCollection<'a>, + outline_cache: &'a mut OutlineCacheSession<'b>, clip_outline: OutlinePath, context_color: AlphaColor<Srgb>, painter: &'a mut dyn DrawSink, @@ -58,23 +63,25 @@ BlendLayer, } -impl Debug for ColrPainter<'_> { +impl Debug for ColrPainter<'_, '_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("ColrPainter()").finish() } } -impl<'a> ColrPainter<'a> { +impl<'a, 'b> ColrPainter<'a, 'b> { /// Create a new COLR painter. pub(crate) fn new( colr_glyph: &'a GlyphColr<'a>, context_color: AlphaColor<Srgb>, painter: &'a mut dyn DrawSink, + outline_cache: &'a mut OutlineCacheSession<'b>, ) -> Self { Self { transforms: vec![colr_glyph.draw_transform], colr_glyph, outline_glyphs: colr_glyph.font_ref.outline_glyphs(), + outline_cache, clip_outline: OutlinePath::new(), context_color, painter, @@ -106,6 +113,20 @@ self.transforms.last().copied().unwrap_or_default() } + fn get_outline(&mut self, glyph_id: GlyphId) -> Option<CachedOutline<'_>> { + let outline_glyph = self.outline_glyphs.get(glyph_id)?; + + Some(self.outline_cache.get_or_insert( + glyph_id.to_u32(), + self.colr_glyph.font_info, + self.colr_glyph.font_info.upem, + FontEmbolden::default(), + VarLookupKey::new(self.colr_glyph.location.coords()), + &outline_glyph, + None, + )) + } + fn palette_index_to_color(&self, palette_index: u16, alpha: f32) -> Option<AlphaColor<Srgb>> { if palette_index != u16::MAX { let color = self @@ -205,34 +226,45 @@ pub(crate) has_non_default_blend: bool, } -pub(crate) fn get_colr_info<'a>( +pub(crate) fn get_colr_info<'a, 'b>( font_ref: &'a FontRef<'a>, color_glyph: &skrifa::color::ColorGlyph<'a>, location: LocationRef<'a>, + outline_cache: &'a mut OutlineCacheSession<'b>, + font_info: FontInfo, ) -> ColrGlyphInfo { - let mut extractor = GlyphInfoExtractor::new(font_ref, location); + let mut extractor = GlyphInfoExtractor::new(font_ref, location, outline_cache, font_info); let _ = color_glyph.paint(location, &mut extractor); extractor.finish() } -struct GlyphInfoExtractor<'a> { +struct GlyphInfoExtractor<'a, 'b> { transforms: Vec<Affine>, clip_stack: Vec<Rect>, coarse_bbox: Option<Rect>, has_non_default_blend: bool, outline_glyphs: OutlineGlyphCollection<'a>, + outline_cache: &'a mut OutlineCacheSession<'b>, location: LocationRef<'a>, + font_info: FontInfo, } -impl<'a> GlyphInfoExtractor<'a> { - fn new(font_ref: &'a FontRef<'a>, location: LocationRef<'a>) -> Self { +impl<'a, 'b> GlyphInfoExtractor<'a, 'b> { + fn new( + font_ref: &'a FontRef<'a>, + location: LocationRef<'a>, + outline_cache: &'a mut OutlineCacheSession<'b>, + font_info: FontInfo, + ) -> Self { Self { transforms: vec![Affine::IDENTITY], clip_stack: Vec::new(), coarse_bbox: None, has_non_default_blend: false, outline_glyphs: font_ref.outline_glyphs(), + outline_cache, location, + font_info, } } @@ -257,6 +289,20 @@ self.cur_transform().transform_rect_bbox(rect) } + fn get_outline(&mut self, glyph_id: GlyphId) -> Option<CachedOutline<'_>> { + let outline_glyph = self.outline_glyphs.get(glyph_id)?; + + Some(self.outline_cache.get_or_insert( + glyph_id.to_u32(), + self.font_info, + self.font_info.upem, + FontEmbolden::default(), + VarLookupKey::new(self.location.coords()), + &outline_glyph, + None, + )) + } + fn finish(self) -> ColrGlyphInfo { ColrGlyphInfo { bbox: self.coarse_bbox, @@ -265,7 +311,7 @@ } } -impl ColorPainter for ColrPainter<'_> { +impl ColorPainter for ColrPainter<'_, '_> { fn push_transform(&mut self, t: Transform) { self.transforms .push(self.cur_transform() * convert_affine(t)); @@ -276,18 +322,17 @@ } fn push_clip_glyph(&mut self, glyph_id: GlyphId) { - // TODO: Make it possible to use the outline cache for this. - let Some(outline_glyph) = self.outline_glyphs.get(glyph_id) else { - return; + let outline = { + let Some(outline) = self.get_outline(glyph_id) else { + return; + }; + Arc::clone(outline.path) }; self.clip_outline.reuse(); - let _ = outline_glyph.draw( - DrawSettings::unhinted(skrifa::instance::Size::unscaled(), self.colr_glyph.location), - &mut self.clip_outline, - ); - - // Note that the bbox will become stale, but we don't need it anyway here. + // TODO: We can make use of `DrawSink::set_transform` to let the client + // take care of applying it, so we can avoid copying the path. + self.clip_outline.path.extend(outline.iter()); self.clip_outline.path.apply_affine(self.cur_transform()); self.push_clip(); } @@ -464,7 +509,7 @@ } } -impl ColorPainter for GlyphInfoExtractor<'_> { +impl ColorPainter for GlyphInfoExtractor<'_, '_> { fn push_transform(&mut self, t: Transform) { self.transforms .push(self.cur_transform() * convert_affine(t)); @@ -475,21 +520,14 @@ } fn push_clip_glyph(&mut self, glyph_id: GlyphId) { - let mut outline_bbox = ControlBoundsPen::default(); - - // TODO: Make it possible to use the outline cache for this. - let Some(outline_glyph) = self.outline_glyphs.get(glyph_id) else { - return; + let outline_bbox = { + let Some(outline) = self.get_outline(glyph_id) else { + return; + }; + outline.bbox }; - let _ = outline_glyph.draw( - DrawSettings::unhinted(skrifa::instance::Size::unscaled(), self.location), - &mut outline_bbox, - ); - - if let Some(outline_bbox) = outline_bbox.bounding_box().map(convert_bounding_box) { - self.push_clip_bbox(self.transform_rect(outline_bbox)); - } + self.push_clip_bbox(self.transform_rect(outline_bbox)); } fn push_clip_box(&mut self, clip_box: BoundingBox<f32>) {
diff --git a/glifo/src/glyph.rs b/glifo/src/glyph.rs index 0d6d96a..98ed222 100644 --- a/glifo/src/glyph.rs +++ b/glifo/src/glyph.rs
@@ -178,6 +178,17 @@ pub(crate) area: Rect, } +/// Basic metadata about a font. +#[derive(Clone, Copy, Debug)] +pub(crate) struct FontInfo { + /// Unique identifier for the font data. + pub(crate) id: u64, + /// Index of the font within the font data. + pub(crate) index: u32, + /// Font units per em. + pub(crate) upem: f32, +} + /// A glyph defined by a COLR glyph description. /// /// Clients are supposed to first draw the glyph into an intermediate image texture/pixmap @@ -190,6 +201,8 @@ pub location: LocationRef<'a>, /// The font reference. pub font_ref: &'a FontRef<'a>, + /// Basic metadata about the font. + pub(crate) font_info: FontInfo, /// The transform to apply to the glyph. pub draw_transform: Affine, /// The rectangular area that should be filled with the rendered representation of the @@ -346,19 +359,18 @@ let mut outline_cache_session = OutlineCacheSession::new( self.outline_cache, - VarLookupKey(self.prepared_run.normalized_coords), + VarLookupKey::new(self.prepared_run.normalized_coords), ); let PreparedGlyphRun { draw_props, run_size: _, + font_info, font_embolden, normalized_coords, hinting_instance, .. } = self.prepared_run; - let font_id = self.prepared_run.font.data.id(); - let font_index = self.prepared_run.font.index; let hinted = hinting_instance.is_some(); let colr_bitmap_cache_enabled = self @@ -374,7 +386,7 @@ let context_color = renderer.get_context_color(); let context_color_packed = pack_color(context_color); let scale_props = - GlyphScaleProperties::new(draw_props.font_size, self.prepared_run.upem, hinted, style); + GlyphScaleProperties::new(draw_props.font_size, font_info.upem, hinted, style); for glyph in self.glyph_iterator.clone() { // TODO: Add a mechanism such that glyphs that are completely outside of the viewport @@ -392,8 +404,8 @@ let outline_cache_key = outline_cache_enabled.then(|| { let fractional_x = outline_transform.translation().x.fract() as f32; GlyphCacheKey::new( - font_id, - font_index, + font_info.id, + font_info.index, glyph.id, draw_props.font_size, hinted, @@ -421,20 +433,21 @@ let location = LocationRef::new(normalized_coords); let metrics = calculate_colr_metrics( draw_props.font_size, - self.prepared_run.upem, draw_props, glyph, &font_ref, &color_glyph, location, + &mut outline_cache_session, + font_info, ); let transform = calculate_colr_transform(&metrics); // COLR glyphs are never hinted and have no sub-pixel offset; // context_color is part of the key because it affects painted layers. let cache_key = colr_bitmap_cache_enabled.then(|| GlyphCacheKey { - font_id, - font_index, + font_id: font_info.id, + font_index: font_info.index, glyph_id: glyph.id, size_bits: draw_props.font_size.to_bits(), hinted: false, @@ -469,8 +482,13 @@ } // Cache miss — rasterize the COLR glyph from scratch. - let glyph_type = - create_colr_glyph(&font_ref, &metrics, color_glyph, normalized_coords); + let glyph_type = create_colr_glyph( + &font_ref, + &metrics, + color_glyph, + normalized_coords, + font_info, + ); let prepared_glyph = PreparedGlyph { glyph_type, @@ -478,8 +496,18 @@ cache_key, }; match style { - Style::Fill => fill_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), - Style::Stroke => stroke_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), + Style::Fill => fill_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), + Style::Stroke => stroke_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), } continue; } @@ -509,7 +537,7 @@ &pixmap, draw_props, draw_props.font_size, - self.prepared_run.upem, + font_info.upem, &bitmap_glyph, &bitmaps, ); @@ -517,8 +545,8 @@ // Bitmaps are not hinted and have no sub-pixel offset or // context color; variation coords are irrelevant for fixed strikes. let cache_key = colr_bitmap_cache_enabled.then(|| GlyphCacheKey { - font_id, - font_index, + font_id: font_info.id, + font_index: font_info.index, glyph_id: glyph.id, size_bits: bitmap_ppem.to_bits(), hinted: false, @@ -549,8 +577,18 @@ cache_key, }; match style { - Style::Fill => fill_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), - Style::Stroke => stroke_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), + Style::Fill => fill_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), + Style::Stroke => stroke_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), } continue; } @@ -567,8 +605,7 @@ let glyph_type = create_outline_glyph( glyph.id, - font_id, - font_index, + font_info, &mut outline_cache_session, scale_props.cache_size, scale_props.draw_scale, @@ -584,8 +621,18 @@ cache_key: outline_cache_key, }; match style { - Style::Fill => fill_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), - Style::Stroke => stroke_glyph(renderer, prepared_glyph, &mut self.atlas_cacher), + Style::Fill => fill_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), + Style::Stroke => stroke_glyph( + renderer, + prepared_glyph, + &mut self.atlas_cacher, + &mut outline_cache_session, + ), } } } @@ -638,6 +685,7 @@ let PreparedGlyphRun { draw_props, + font_info, font_embolden, hinting_instance, .. @@ -652,7 +700,7 @@ // simply drawing in global space, but we need to invert it for drawing decorations. let scale_props = GlyphScaleProperties::new( draw_props.font_size, - self.prepared_run.upem, + font_info.upem, hinting_instance.is_some(), Style::Fill, ); @@ -678,7 +726,7 @@ let layout_y1 = f64::from(-offset + size); // Get a cache session for this font's variation coordinates - let var_key = VarLookupKey(self.prepared_run.normalized_coords); + let var_key = VarLookupKey::new(self.prepared_run.normalized_coords); let mut outline_cache_session = OutlineCacheSession::new(self.outline_cache, var_key); // Collect and merge exclusion zones from all glyphs. @@ -694,8 +742,7 @@ let cached = outline_cache_session.get_or_insert( glyph.id, - self.prepared_run.font.data.id(), - self.prepared_run.font.index, + font_info, scale_props.cache_size, font_embolden, var_key, @@ -1018,9 +1065,8 @@ /// without any positioning information. fn create_outline_glyph<'a>( glyph_id: u32, - font_id: u64, - font_index: u32, - outline_cache: &'a mut OutlineCacheSession<'_>, + font_info: FontInfo, + outline_cache: &mut OutlineCacheSession<'_>, size: f32, scale: f64, embolden: FontEmbolden, @@ -1030,11 +1076,10 @@ ) -> GlyphType<'a> { let cached = outline_cache.get_or_insert( glyph_id, - font_id, - font_index, + font_info, size, embolden, - VarLookupKey(normalized_coords), + VarLookupKey::new(normalized_coords), outline_glyph, hinting_instance, ); @@ -1197,17 +1242,18 @@ /// /// This computes the intermediate values needed for both creating the `GlyphColr` /// and calculating its positioning transform. -fn calculate_colr_metrics( +fn calculate_colr_metrics<'a>( font_size: f32, - upem: f32, draw_props: DrawProps, glyph: Glyph, - font_ref: &FontRef<'_>, - color_glyph: &skrifa::color::ColorGlyph<'_>, - location: LocationRef<'_>, + font_ref: &'a FontRef<'a>, + color_glyph: &skrifa::color::ColorGlyph<'a>, + location: LocationRef<'a>, + outline_cache: &mut OutlineCacheSession<'_>, + font_info: FontInfo, ) -> ColrMetrics { // The scale factor we need to apply to scale from font units to our font size. - let font_size_scale = (font_size / upem) as f64; + let font_size_scale = (font_size / font_info.upem) as f64; let transform = draw_props.positioned_transform(glyph); // Estimate the size of the intermediate pixmap. Ideally, the intermediate bitmap should have @@ -1219,7 +1265,7 @@ }; // TODO: Cache this across frames. - let colr_info = get_colr_info(font_ref, color_glyph, location); + let colr_info = get_colr_info(font_ref, color_glyph, location, outline_cache, font_info); let bbox = color_glyph // First try to get the clip bbox from the COLR table, // as this one has the highest priority. @@ -1292,6 +1338,7 @@ metrics: &ColrMetrics, color_glyph: skrifa::color::ColorGlyph<'a>, normalized_coords: &'a [skrifa::instance::NormalizedCoord], + font_info: FontInfo, ) -> GlyphType<'a> { let (pix_width, pix_height) = ( metrics.scaled_bbox.width().ceil() as u16, @@ -1325,6 +1372,7 @@ pix_height, draw_transform, has_non_default_blend: metrics.has_non_default_blend, + font_info, })) } @@ -1370,8 +1418,8 @@ struct PreparedGlyphRun<'a> { /// The underlying font data. font: FontData, - /// Font units per em for the underlying font. - upem: f32, + /// Basic metadata about the underlying font. + font_info: FontInfo, // The fact that we store `run_size` and `glyph_transform` here, as well // as having more transforms and an effective font size inside of the `draw_props` field is pretty // confusing, so here is a brief explanation: @@ -1447,7 +1495,7 @@ // HintingInstance doesn't implement Debug so we have to do this manually :( f.debug_struct("PreparedGlyphRun") .field("font", &self.font) - .field("upem", &self.upem) + .field("font_info", &self.font_info) .field("run_size", &self.run_size) .field("font_embolden", &self.font_embolden) .field("glyph_transform", &self.glyph_transform) @@ -1542,10 +1590,15 @@ .map(|h| h.units_per_em()) .unwrap() .into(); + let font_info = FontInfo { + id: run.font.data.id(), + index: run.font.index, + upem, + }; PreparedGlyphRun { font: run.font, - upem, + font_info, run_size: run.font_size, font_embolden: run.font_embolden, glyph_transform: run.glyph_transform, @@ -1818,7 +1871,7 @@ } } -struct OutlineCacheSession<'a> { +pub(crate) struct OutlineCacheSession<'a> { map: &'a mut HashMap<OutlineKey, OutlineEntry>, free_list: &'a mut Vec<OutlinePath>, serial: u32, @@ -1827,7 +1880,7 @@ impl<'a> OutlineCacheSession<'a> { fn new(outline_cache: &'a mut OutlineCache, var_key: VarLookupKey<'_>) -> Self { - let map = if var_key.0.is_empty() { + let map = if var_key.coords().is_empty() { &mut outline_cache.static_map } else { match outline_cache @@ -1847,11 +1900,10 @@ } } - fn get_or_insert( + pub(crate) fn get_or_insert( &mut self, glyph_id: u32, - font_id: u64, - font_index: u32, + font_info: FontInfo, size: f32, embolden: FontEmbolden, var_key: VarLookupKey<'_>, @@ -1860,8 +1912,8 @@ ) -> CachedOutline<'_> { let key = OutlineKey { glyph_id, - font_id, - font_index, + font_id: font_info.id, + font_index: font_info.index, size_bits: size.to_bits(), embolden_x_bits: f32_bits(embolden.amount.xx), embolden_y_bits: f32_bits(embolden.amount.yy), @@ -1887,7 +1939,7 @@ let draw_settings = if let Some(hinting_instance) = hinting_instance { DrawSettings::hinted(hinting_instance, false) } else { - DrawSettings::unhinted(Size::new(size), var_key.0) + DrawSettings::unhinted(Size::new(size), var_key.coords()) }; drawing_buf.reuse(); @@ -1923,7 +1975,17 @@ /// Lookup key for variable font caches. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -struct VarLookupKey<'a>(&'a [skrifa::instance::NormalizedCoord]); +pub(crate) struct VarLookupKey<'a>(&'a [skrifa::instance::NormalizedCoord]); + +impl<'a> VarLookupKey<'a> { + pub(crate) fn new(coords: &'a [skrifa::instance::NormalizedCoord]) -> Self { + Self(coords) + } + + fn coords(self) -> &'a [skrifa::instance::NormalizedCoord] { + self.0 + } +} impl Equivalent<VarKey> for VarLookupKey<'_> { fn equivalent(&self, other: &VarKey) -> bool {
diff --git a/glifo/src/renderer.rs b/glifo/src/renderer.rs index 6c53580..51a63d2 100644 --- a/glifo/src/renderer.rs +++ b/glifo/src/renderer.rs
@@ -8,7 +8,8 @@ use crate::atlas::{AtlasSlot, GlyphAtlas, GlyphCacheKey, ImageCache, RasterMetrics}; use crate::colr::ColrPainter; use crate::glyph::{ - AtlasCacher, CachedGlyphType, GlyphBitmap, GlyphColr, GlyphOutline, GlyphType, PreparedGlyph, + AtlasCacher, CachedGlyphType, GlyphBitmap, GlyphColr, GlyphOutline, GlyphType, + OutlineCacheSession, PreparedGlyph, }; use crate::interface::{DrawSink, GlyphRenderer}; use crate::util::AffineExt; @@ -43,6 +44,7 @@ renderer: &mut impl GlyphRenderer, prepared_glyph: PreparedGlyph<'_>, atlas_cacher: &mut AtlasCacher<'_>, + outline_cache: &mut OutlineCacheSession<'_>, ) { let AtlasCacher::Enabled(glyph_atlas, image_cache) = atlas_cacher else { let transform = prepared_glyph.transform; @@ -54,7 +56,13 @@ GlyphType::Bitmap(glyph) => render_uncached_bitmap_glyph(renderer, glyph, transform), GlyphType::Colr(glyph) => { let context_color = renderer.get_context_color(); - render_uncached_colr_glyph(renderer, &glyph, transform, context_color); + render_uncached_colr_glyph( + renderer, + &glyph, + transform, + context_color, + outline_cache, + ); } }; }; @@ -106,13 +114,14 @@ key, glyph_atlas, image_cache, + outline_cache, ) { return; } let context_color = renderer.get_context_color(); - render_uncached_colr_glyph(renderer, &glyph, transform, context_color); + render_uncached_colr_glyph(renderer, &glyph, transform, context_color, outline_cache); } } } @@ -123,6 +132,7 @@ renderer: &mut impl GlyphRenderer, prepared_glyph: PreparedGlyph<'_>, atlas_cacher: &mut AtlasCacher<'_>, + outline_cache: &mut OutlineCacheSession<'_>, ) { let AtlasCacher::Enabled(glyph_atlas, image_cache) = atlas_cacher else { let transform = prepared_glyph.transform; @@ -131,7 +141,7 @@ stroke_uncached_outline_glyph(renderer, &glyph.path, glyph.scale, transform); } GlyphType::Bitmap(_) | GlyphType::Colr(_) => { - fill_glyph(renderer, prepared_glyph, atlas_cacher); + fill_glyph(renderer, prepared_glyph, atlas_cacher, outline_cache); } }; }; @@ -159,7 +169,7 @@ stroke_uncached_outline_glyph(renderer, &glyph.path, glyph.scale, transform); } GlyphType::Bitmap(_) | GlyphType::Colr(_) => { - fill_glyph(renderer, prepared_glyph, atlas_cacher); + fill_glyph(renderer, prepared_glyph, atlas_cacher, outline_cache); } } } @@ -215,6 +225,7 @@ glyph: &GlyphColr<'_>, transform: Affine, context_color: AlphaColor<Srgb>, + outline_cache: &mut OutlineCacheSession<'_>, ) { let state = renderer.save_state(); renderer.set_transform(transform); @@ -232,7 +243,7 @@ } // TODO: Maybe ColrPainter can be reused across glyphs? - let mut colr_painter = ColrPainter::new(glyph, context_color, renderer); + let mut colr_painter = ColrPainter::new(glyph, context_color, renderer, outline_cache); colr_painter.paint(); if glyph.has_non_default_blend { renderer.pop_layer(); @@ -320,6 +331,7 @@ context_color: AlphaColor<Srgb>, recorder: &mut AtlasCommandRecorder, atlas_slot: AtlasSlot, + outline_cache: &mut OutlineCacheSession<'_>, ) { recorder.set_transform(Affine::translate(( atlas_slot.x as f64, @@ -334,7 +346,7 @@ } // TODO: Maybe ColrPainter can be reused across glyphs? - let mut colr_painter = ColrPainter::new(glyph, context_color, recorder); + let mut colr_painter = ColrPainter::new(glyph, context_color, recorder, outline_cache); colr_painter.paint(); if glyph.has_non_default_blend { @@ -435,6 +447,7 @@ cache_key: GlyphCacheKey, glyph_atlas: &mut GlyphAtlas, image_cache: &mut ImageCache, + outline_cache: &mut OutlineCacheSession<'_>, ) -> CacheResult { if !supports_atlas_caching(&transform, CachedGlyphType::Colr(Rect::ZERO)) { return CacheResult::UnsupportedTransform; @@ -458,7 +471,7 @@ return CacheResult::AtlasFull; }; - render_colr_to_atlas(glyph, context_color, recorder, atlas_slot); + render_colr_to_atlas(glyph, context_color, recorder, atlas_slot, outline_cache); render_from_atlas( renderer,