diff --git a/src/OT/Color/COLR/COLR.hh b/src/OT/Color/COLR/COLR.hh index f4f5e6573..309ac2101 100644 --- a/src/OT/Color/COLR/COLR.hh +++ b/src/OT/Color/COLR/COLR.hh @@ -47,6 +47,11 @@ namespace OT { struct hb_paint_context_t; } +struct hb_colr_scratch_t +{ + hb_paint_extents_context_t paint_extents; +}; + namespace OT { struct COLR; @@ -2079,6 +2084,8 @@ struct COLR { static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; + bool has_data () const { return has_v0_data () || version; } + bool has_v0_data () const { return numBaseGlyphs; } bool has_v1_data () const { @@ -2115,13 +2122,21 @@ struct COLR ~accelerator_t () { this->colr.destroy (); } + bool has_data () const { return colr->has_data (); } + #ifndef HB_NO_PAINT bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { - return colr->get_extents (font, glyph, extents); + if (unlikely (!has_data ())) return false; + + hb_colr_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = colr->get_extents (font, glyph, extents, *scratch); + release_scratch (scratch); + return ret; } bool paint_glyph (hb_font_t *font, @@ -2131,7 +2146,13 @@ struct COLR hb_color_t foreground, bool clip = true) const { - return colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip); + if (unlikely (!has_data ())) return false; + + hb_colr_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch); + release_scratch (scratch); + return ret; } #endif @@ -2168,8 +2189,34 @@ struct COLR const DeltaSetIndexMap *get_delta_set_index_map_ptr () const { return colr->get_delta_set_index_map_ptr (); } + private: + + hb_colr_scratch_t *acquire_scratch () const + { + hb_colr_scratch_t *scratch = cached_scratch.get_acquire (); + + if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) + { + scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t)); + if (unlikely (!scratch)) + return nullptr; + } + + return scratch; + } + void release_scratch (hb_colr_scratch_t *scratch) const + { + if (!cached_scratch.cmpexch (nullptr, scratch)) + { + scratch->~hb_colr_scratch_t (); + hb_free (scratch); + } + } + public: hb_blob_ptr_t colr; + private: + hb_atomic_ptr_t cached_scratch; }; void closure_glyphs (hb_codepoint_t glyph, @@ -2541,7 +2588,10 @@ struct COLR #ifndef HB_NO_PAINT bool - get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_colr_scratch_t &scratch) const { ItemVarStoreInstancer instancer (get_var_store_ptr (), @@ -2555,10 +2605,10 @@ struct COLR } auto *extents_funcs = hb_paint_extents_get_funcs (); - hb_paint_extents_context_t extents_data; - bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0)); + scratch.paint_extents.clear (); + bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch); - hb_extents_t e = extents_data.get_extents (); + auto e = scratch.paint_extents.get_extents (); if (e.is_void ()) { extents->x_bearing = 0; @@ -2604,7 +2654,12 @@ struct COLR #ifndef HB_NO_PAINT bool - paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const + paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *funcs, void *data, + unsigned int palette_index, hb_color_t foreground, + bool clip, + hb_colr_scratch_t &scratch) const { ItemVarStoreInstancer instancer (get_var_store_ptr (), get_delta_set_index_map_ptr (), @@ -2639,15 +2694,16 @@ struct COLR else { auto *extents_funcs = hb_paint_extents_get_funcs (); - hb_paint_extents_context_t extents_data; + scratch.paint_extents.clear (); paint_glyph (font, glyph, - extents_funcs, &extents_data, + extents_funcs, &scratch.paint_extents, palette_index, foreground, - false); + false, + scratch); - hb_extents_t extents = extents_data.get_extents (); - is_bounded = extents_data.is_bounded (); + auto extents = scratch.paint_extents.get_extents (); + is_bounded = scratch.paint_extents.is_bounded (); c.funcs->push_clip_rectangle (c.data, extents.xmin, diff --git a/src/hb-geometry.hh b/src/hb-geometry.hh index 11bce0cf7..85ddd2abe 100644 --- a/src/hb-geometry.hh +++ b/src/hb-geometry.hh @@ -243,7 +243,7 @@ struct hb_bounds_t EMPTY, }; - hb_bounds_t (status_t status) : status (status) {} + hb_bounds_t (status_t status = UNBOUNDED) : status (status) {} hb_bounds_t (const hb_extents_t &extents) : status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {} diff --git a/src/hb-paint-extents.hh b/src/hb-paint-extents.hh index 2d4491e07..708af4a86 100644 --- a/src/hb-paint-extents.hh +++ b/src/hb-paint-extents.hh @@ -35,13 +35,22 @@ typedef struct hb_paint_extents_context_t hb_paint_extents_context_t; struct hb_paint_extents_context_t { - hb_paint_extents_context_t () + void clear () { + transforms.clear (); + clips.clear (); + groups.clear (); + transforms.push (hb_transform_t{}); clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED}); groups.push (hb_bounds_t{hb_bounds_t::EMPTY}); } + hb_paint_extents_context_t () + { + clear (); + } + hb_extents_t get_extents () { return groups.tail().extents;