diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 0f44ee4d5..521b3ee92 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -110,12 +110,24 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; +#ifndef HB_NO_VAR + const OT::HVARVVAR &HVAR = *hmtx.var_table; + const OT::VariationStore &varStore = &HVAR + HVAR.varStore; + OT::VariationStore::cache_t *cache = font->num_coords ? varStore.create_cache () : nullptr; +#else + OT::VariationStore::cache_t *cache = nullptr; +#endif + for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font)); + *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, cache)); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + +#ifndef HB_NO_VAR + OT::VariationStore::destroy_cache (cache); +#endif } #ifndef HB_NO_VERTICAL @@ -132,12 +144,26 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; if (vmtx.has_data ()) + { +#ifndef HB_NO_VAR + const OT::HVARVVAR &VVAR = *vmtx.var_table; + const OT::VariationStore &varStore = &VVAR + VVAR.varStore; + OT::VariationStore::cache_t *cache = font->num_coords ? varStore.create_cache () : nullptr; +#else + OT::VariationStore::cache_t *cache = nullptr; +#endif + for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); + *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, cache)); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + +#ifndef HB_NO_VAR + OT::VariationStore::destroy_cache (cache); +#endif + } else { hb_font_extents_t font_extents; diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index d5e1fc91d..d0e46e0b0 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -242,7 +242,7 @@ struct hmtxvmtx return side_bearing; if (var_table.get_length ()) - return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else @@ -284,7 +284,8 @@ struct hmtxvmtx } unsigned int get_advance (hb_codepoint_t glyph, - hb_font_t *font) const + hb_font_t *font, + VariationStore::cache_t *store_cache = nullptr) const { unsigned int advance = get_advance (glyph); @@ -293,7 +294,7 @@ struct hmtxvmtx return advance; if (var_table.get_length ()) - return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! + return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?! return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else @@ -310,7 +311,7 @@ struct hmtxvmtx unsigned int default_advance; - private: + public: hb_blob_ptr_t table; hb_blob_ptr_t var_table; }; diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index b644df708..3e061b7c6 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -2601,14 +2601,27 @@ struct VarRegionAxis DEFINE_SIZE_STATIC (6); }; +#define REGION_CACHE_ITEM_CACHE_INVALID 2.f + struct VarRegionList { + using cache_t = float; + float evaluate (unsigned int region_index, - const int *coords, unsigned int coord_len) const + const int *coords, unsigned int coord_len, + cache_t *cache = nullptr) const { if (unlikely (region_index >= regionCount)) return 0.; + float *cached = nullptr; + if (cache) + { + cached = &(cache[region_index]); + if (likely (*cached != REGION_CACHE_ITEM_CACHE_INVALID)) + return *cached; + } + const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount); float v = 1.; @@ -2618,9 +2631,16 @@ struct VarRegionList int coord = i < coord_len ? coords[i] : 0; float factor = axes[i].evaluate (coord); if (factor == 0.f) + { + if (cache) + *cached = 0.; return 0.; + } v *= factor; } + + if (cache) + *cached = v; return v; } @@ -2678,7 +2698,8 @@ struct VarData float get_delta (unsigned int inner, const int *coords, unsigned int coord_count, - const VarRegionList ®ions) const + const VarRegionList ®ions, + VarRegionList::cache_t *cache = nullptr) const { if (unlikely (inner >= itemCount)) return 0.; @@ -2695,13 +2716,13 @@ struct VarData const HBINT16 *scursor = reinterpret_cast (row); for (; i < scount; i++) { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); delta += scalar * *scursor++; } const HBINT8 *bcursor = reinterpret_cast (scursor); for (; i < count; i++) { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); delta += scalar * *bcursor++; } @@ -2846,9 +2867,28 @@ struct VarData struct VariationStore { + using cache_t = VarRegionList::cache_t; + + cache_t *create_cache () const + { + auto &r = this+regions; + unsigned count = r.regionCount; + + float *cache = (float *) hb_malloc (sizeof (float) * count); + if (unlikely (!cache)) return nullptr; + + for (unsigned i = 0; i < count; i++) + cache[i] = REGION_CACHE_ITEM_CACHE_INVALID; + + return cache; + } + + static void destroy_cache (cache_t *cache) { hb_free (cache); } + private: float get_delta (unsigned int outer, unsigned int inner, - const int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count, + VarRegionList::cache_t *cache = nullptr) const { #ifdef HB_NO_VAR return 0.f; @@ -2859,16 +2899,18 @@ struct VariationStore return (this+dataSets[outer]).get_delta (inner, coords, coord_count, - this+regions); + this+regions, + cache); } public: float get_delta (unsigned int index, - const int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count, + VarRegionList::cache_t *cache = nullptr) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; - return get_delta (outer, inner, coords, coord_count); + return get_delta (outer, inner, coords, coord_count, cache); } bool sanitize (hb_sanitize_context_t *c) const @@ -2995,6 +3037,8 @@ struct VariationStore DEFINE_SIZE_ARRAY_SIZED (8, dataSets); }; +#undef REGION_CACHE_ITEM_CACHE_INVALID + /* * Feature Variations */ @@ -3462,11 +3506,15 @@ struct VariationDevice private: - hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const - { return font->em_scalef_x (get_delta (font, store)); } + hb_position_t get_x_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const + { return font->em_scalef_x (get_delta (font, store, store_cache)); } - hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const - { return font->em_scalef_y (get_delta (font, store)); } + hb_position_t get_y_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const + { return font->em_scalef_y (get_delta (font, store, store_cache)); } VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const { @@ -3500,9 +3548,11 @@ struct VariationDevice private: - float get_delta (hb_font_t *font, const VariationStore &store) const + float get_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const { - return store.get_delta (varIdx, font->coords, font->num_coords); + return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache); } protected: @@ -3525,7 +3575,9 @@ struct DeviceHeader struct Device { - hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const + hb_position_t get_x_delta (hb_font_t *font, + const VariationStore &store=Null (VariationStore), + VariationStore::cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -3535,13 +3587,15 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - return u.variation.get_x_delta (font, store); + return u.variation.get_x_delta (font, store, store_cache); #endif default: return 0; } } - hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const + hb_position_t get_y_delta (hb_font_t *font, + const VariationStore &store=Null (VariationStore), + VariationStore::cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -3551,7 +3605,7 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - return u.variation.get_y_delta (font, store); + return u.variation.get_y_delta (font, store, store_cache); #endif default: return 0; diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 2f9186a2a..0dbfa016a 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -146,23 +146,24 @@ struct ValueFormat : HBUINT16 if (!use_x_device && !use_y_device) return ret; const VariationStore &store = c->var_store; + auto *cache = c->var_store_cache; /* pixel -> fractional pixel */ if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store); + if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); values++; } if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store); + if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); values++; } if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store); + if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); values++; } if (format & yAdvDevice) { /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store); + if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); values++; } return ret; @@ -465,9 +466,9 @@ struct AnchorFormat3 *y = font->em_fscale_y (yCoordinate); if (font->x_ppem || font->num_coords) - *x += (this+xDeviceTable).get_x_delta (font, c->var_store); + *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); if (font->y_ppem || font->num_coords) - *y += (this+yDeviceTable).get_y_delta (font, c->var_store); + *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index c9750ff63..d45499fd4 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -621,16 +621,17 @@ struct hb_ot_apply_context_t : skipping_iterator_t iter_input, iter_context; + unsigned int table_index; /* GSUB/GPOS */ hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; recurse_func_t recurse_func; const GDEF &gdef; const VariationStore &var_store; + VariationStore::cache_t *var_store_cache; hb_direction_t direction; hb_mask_t lookup_mask; - unsigned int table_index; /* GSUB/GPOS */ unsigned int lookup_index; unsigned int lookup_props; unsigned int nesting_level_left; @@ -648,6 +649,7 @@ struct hb_ot_apply_context_t : hb_font_t *font_, hb_buffer_t *buffer_) : iter_input (), iter_context (), + table_index (table_index_), font (font_), face (font->face), buffer (buffer_), recurse_func (nullptr), gdef ( @@ -658,9 +660,15 @@ struct hb_ot_apply_context_t : #endif ), var_store (gdef.get_var_store ()), + var_store_cache ( +#ifndef HB_NO_VAR + table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr +#else + nullptr +#endif + ), direction (buffer_->props.direction), lookup_mask (1), - table_index (table_index_), lookup_index ((unsigned int) -1), lookup_props (0), nesting_level_left (HB_MAX_NESTING_LEVEL), @@ -669,7 +677,15 @@ struct hb_ot_apply_context_t : auto_zwj (true), per_syllable (false), random (false), - random_state (1) { init_iters (); } + random_state (1) + { init_iters (); } + + ~hb_ot_apply_context_t () + { +#ifndef HB_NO_VAR + VariationStore::destroy_cache (var_store_cache); +#endif + } void init_iters () { diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index e9d90352f..56efcdbee 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -319,10 +319,15 @@ struct HVARVVAR hvar_plan.index_map_plans.as_array ())); } - float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const + float get_advance_var (hb_codepoint_t glyph, + hb_font_t *font, + VariationStore::cache_t *store_cache = nullptr) const { uint32_t varidx = (this+advMap).map (glyph); - return (this+varStore).get_delta (varidx, font->coords, font->num_coords); + return (this+varStore).get_delta (varidx, + font->coords, + font->num_coords, + store_cache); } float get_side_bearing_var (hb_codepoint_t glyph, @@ -335,7 +340,7 @@ struct HVARVVAR bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } - protected: + public: FixedVersion<>version; /* Version of the metrics variation table * initially set to 0x00010000u */ Offset32To