From 894fee6db379e6dd7dc67075b664ed7563f13bb6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 9 Dec 2024 21:52:39 -0700 Subject: [PATCH 1/4] [GVAR] Implement table Unused. It's just like `gvar` but with 24bit glyphCount. --- src/hb-ot-var-gvar-table.hh | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 973f2d98a..bc821486b 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -36,6 +36,7 @@ * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar */ #define HB_OT_TAG_gvar HB_TAG('g','v','a','r') +#define HB_OT_TAG_GVAR HB_TAG('G','V','A','R') struct hb_glyf_scratch_t { @@ -316,9 +317,10 @@ struct glyph_variations_t } }; -struct gvar +template +struct gvar_GVAR { - static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; + static constexpr hb_tag_t tableTag = TableTag; bool sanitize_shallow (hb_sanitize_context_t *c) const { @@ -371,7 +373,7 @@ struct gvar bool force_long_offsets) const { TRACE_SERIALIZE (this); - gvar *out = c->allocate_min (); + gvar_GVAR *out = c->allocate_min (); if (unlikely (!out)) return_trace (false); out->version.major = 1; @@ -443,7 +445,7 @@ struct gvar unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0; - gvar *out = c->serializer->allocate_min (); + gvar_GVAR *out = c->serializer->allocate_min (); if (unlikely (!out)) return_trace (false); out->version.major = 1; @@ -579,7 +581,7 @@ struct gvar { accelerator_t (hb_face_t *face) { - table = hb_sanitize_context_t ().reference_table (face); + table = hb_sanitize_context_t ().reference_table (face); /* If sanitize failed, set glyphCount to 0. */ glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0; @@ -875,7 +877,7 @@ struct gvar unsigned int get_axis_count () const { return table->axisCount; } private: - hb_blob_ptr_t table; + hb_blob_ptr_t table; unsigned glyphCount; hb_vector_t> shared_tuple_active_idx; }; @@ -893,7 +895,7 @@ struct gvar NNOffset32To> sharedTuples; /* Offset from the start of this table to the shared tuple records. * Array of tuple records shared across all glyph variation data tables. */ - HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of + GidOffsetType glyphCountX; /* The number of glyphs in this font. This must match the number of * glyphs stored elsewhere in the font. */ HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the @@ -908,9 +910,15 @@ struct gvar DEFINE_SIZE_ARRAY (20, offsetZ); }; +using gvar = gvar_GVAR; +using GVAR = gvar_GVAR; + struct gvar_accelerator_t : gvar::accelerator_t { gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {} }; +struct GVAR_accelerator_t : GVAR::accelerator_t { + GVAR_accelerator_t (hb_face_t *face) : GVAR::accelerator_t (face) {} +}; } /* namespace OT */ From ffe955b9f9f3501a7cb766c28fc6dd87f71c6c74 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 26 Feb 2025 13:40:18 -0700 Subject: [PATCH 2/4] [GVAR] Change offsetToData size to 24bit As per https://github.com/harfbuzz/boring-expansion-spec/issues/162 --- src/hb-ot-var-common.hh | 8 +++++--- src/hb-ot-var-cvar-table.hh | 26 +++++++++++++------------- src/hb-ot-var-gvar-table.hh | 25 ++++++++++++++----------- src/test-tuple-varstore.cc | 8 ++++---- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index e1e6ce16c..8eec5195a 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -841,6 +841,7 @@ struct tuple_delta_t { return (i >= end) ? start : (i + 1); } }; +template struct TupleVariationData { bool sanitize (hb_sanitize_context_t *c) const @@ -1521,15 +1522,16 @@ struct TupleVariationData * low 12 bits are the number of tuple variation tables * for this glyph. The number of tuple variation tables * can be any number between 1 and 4095. */ - Offset16To + OffsetTo data; /* Offset from the start of the base table * to the serialized data. */ /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */ public: - DEFINE_SIZE_MIN (4); + DEFINE_SIZE_MIN (2 + OffType::static_size); }; -using tuple_variations_t = TupleVariationData::tuple_variations_t; +// TODO: Move tuple_variations_t to outside of TupleVariationData +using tuple_variations_t = TupleVariationData::tuple_variations_t; struct item_variations_t { using region_t = const hb_hashmap_t*; diff --git a/src/hb-ot-var-cvar-table.hh b/src/hb-ot-var-cvar-table.hh index 3931382f1..f8ae0c803 100644 --- a/src/hb-ot-var-cvar-table.hh +++ b/src/hb-ot-var-cvar-table.hh @@ -50,7 +50,7 @@ struct cvar tupleVariationData.sanitize (c)); } - const TupleVariationData* get_tuple_var_data (void) const + const TupleVariationData<>* get_tuple_var_data (void) const { return &tupleVariationData; } bool decompile_tuple_variations (unsigned axis_count, @@ -58,12 +58,12 @@ struct cvar hb_blob_t *blob, bool is_gvar, const hb_map_t *axes_old_index_tag_map, - TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const + TupleVariationData<>::tuple_variations_t& tuple_variations /* OUT */) const { hb_vector_t shared_indices; - TupleVariationData::tuple_iterator_t iterator; + TupleVariationData<>::tuple_iterator_t iterator; hb_bytes_t var_data_bytes = blob->as_bytes ().sub_array (4); - if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this, + if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, this, shared_indices, &iterator)) return false; @@ -77,16 +77,16 @@ struct cvar static bool calculate_cvt_deltas (unsigned axis_count, hb_array_t coords, unsigned num_cvt_item, - const TupleVariationData *tuple_var_data, + const TupleVariationData<> *tuple_var_data, const void *base, hb_vector_t& cvt_deltas /* OUT */) { if (!coords) return true; hb_vector_t shared_indices; - TupleVariationData::tuple_iterator_t iterator; + TupleVariationData<>::tuple_iterator_t iterator; unsigned var_data_length = tuple_var_data->get_size (axis_count); hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast (tuple_var_data), var_data_length); - if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, base, + if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, base, shared_indices, &iterator)) return true; /* isn't applied at all */ @@ -107,14 +107,14 @@ struct cvar bool has_private_points = iterator.current_tuple->has_private_points (); if (has_private_points && - !TupleVariationData::decompile_points (p, private_indices, end)) + !TupleVariationData<>::decompile_points (p, private_indices, end)) return false; const hb_vector_t &indices = has_private_points ? private_indices : shared_indices; bool apply_to_all = (indices.length == 0); unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length; if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false; - if (unlikely (!TupleVariationData::decompile_deltas (p, unpacked_deltas, end))) return false; + if (unlikely (!TupleVariationData<>::decompile_deltas (p, unpacked_deltas, end))) return false; for (unsigned int i = 0; i < num_deltas; i++) { @@ -129,7 +129,7 @@ struct cvar } bool serialize (hb_serialize_context_t *c, - TupleVariationData::tuple_variations_t& tuple_variations) const + TupleVariationData<>::tuple_variations_t& tuple_variations) const { TRACE_SERIALIZE (this); if (!tuple_variations) return_trace (false); @@ -144,7 +144,7 @@ struct cvar if (c->plan->all_axes_pinned) return_trace (false); - OT::TupleVariationData::tuple_variations_t tuple_variations; + OT::TupleVariationData<>::tuple_variations_t tuple_variations; unsigned axis_count = c->plan->axes_old_index_tag_map.get_population (); const hb_tag_t cvt = HB_TAG('c','v','t',' '); @@ -169,7 +169,7 @@ struct cvar } static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan, - const TupleVariationData *tuple_var_data, + const TupleVariationData<> *tuple_var_data, const void *base) { const hb_tag_t cvt = HB_TAG('c','v','t',' '); @@ -209,7 +209,7 @@ struct cvar protected: FixedVersion<>version; /* Version of the CVT variation table * initially set to 0x00010000u */ - TupleVariationData tupleVariationData; /* TupleVariationDate for cvar table */ + TupleVariationData<> tupleVariationData; /* TupleVariationDate for cvar table */ public: DEFINE_SIZE_MIN (8); }; diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index bc821486b..b9f1b22db 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -59,12 +59,13 @@ struct hb_glyf_scratch_t namespace OT { -struct GlyphVariationData : TupleVariationData -{}; - +template struct glyph_variations_t { - using tuple_variations_t = TupleVariationData::tuple_variations_t; + // TODO: Move tuple_variations_t to outside of TupleVariationData + using tuple_variations_t = typename TupleVariationData::tuple_variations_t; + using GlyphVariationData = TupleVariationData; + hb_vector_t glyph_variations; hb_vector_t compiled_shared_tuples; @@ -106,7 +107,7 @@ struct glyph_variations_t hb_bytes_t var_data = new_gid_var_data_map.get (new_gid); const GlyphVariationData* p = reinterpret_cast (var_data.arrayZ); - GlyphVariationData::tuple_iterator_t iterator; + typename GlyphVariationData::tuple_iterator_t iterator; tuple_variations_t tuple_vars; hb_vector_t shared_indices; @@ -280,7 +281,7 @@ struct glyph_variations_t hb_codepoint_t last_gid = 0; unsigned idx = 0; - TupleVariationData* cur_glyph = c->start_embed (); + GlyphVariationData* cur_glyph = c->start_embed (); if (!cur_glyph) return_trace (false); for (auto &_ : it) { @@ -294,7 +295,7 @@ struct glyph_variations_t if (idx >= glyph_variations.length) return_trace (false); if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false); - TupleVariationData* next_glyph = c->start_embed (); + GlyphVariationData* next_glyph = c->start_embed (); glyph_offset += (char *) next_glyph - (char *) cur_glyph; if (long_offset) @@ -322,6 +323,8 @@ struct gvar_GVAR { static constexpr hb_tag_t tableTag = TableTag; + using GlyphVariationData = TupleVariationData; + bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -339,7 +342,7 @@ struct gvar_GVAR { return sanitize_shallow (c); } bool decompile_glyph_variations (hb_subset_context_t *c, - glyph_variations_t& glyph_vars /* OUT */) const + glyph_variations_t& glyph_vars /* OUT */) const { hb_hashmap_t new_gid_var_data_map; auto it = hb_iter (c->plan->new_to_old_gid_list); @@ -366,7 +369,7 @@ struct gvar_GVAR template bool serialize (hb_serialize_context_t *c, - const glyph_variations_t& glyph_vars, + const glyph_variations_t& glyph_vars, Iterator it, unsigned axis_count, unsigned num_glyphs, @@ -415,7 +418,7 @@ struct gvar_GVAR bool instantiate (hb_subset_context_t *c) const { TRACE_SUBSET (this); - glyph_variations_t glyph_vars; + glyph_variations_t glyph_vars; if (!decompile_glyph_variations (c, glyph_vars)) return_trace (false); @@ -660,7 +663,7 @@ struct gvar_GVAR auto &shared_indices = scratch.shared_indices; shared_indices.clear (); - GlyphVariationData::tuple_iterator_t iterator; + typename GlyphVariationData::tuple_iterator_t iterator; if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount, var_data_bytes.arrayZ, shared_indices, &iterator)) diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc index afba20f28..9fdbacafa 100644 --- a/src/test-tuple-varstore.cc +++ b/src/test-tuple-varstore.cc @@ -38,15 +38,15 @@ test_decompile_cvar () hb_map_t axis_idx_tag_map; axis_idx_tag_map.set (0, axis_tag); - OT::TupleVariationData::tuple_variations_t tuple_variations; + OT::TupleVariationData<>::tuple_variations_t tuple_variations; hb_vector_t shared_indices; - OT::TupleVariationData::tuple_iterator_t iterator; + OT::TupleVariationData<>::tuple_iterator_t iterator; - const OT::TupleVariationData* tuple_var_data = reinterpret_cast (cvar_data + 4); + const OT::TupleVariationData<>* tuple_var_data = reinterpret_cast*> (cvar_data + 4); unsigned len = sizeof (cvar_data); hb_bytes_t var_data_bytes{(const char* ) cvar_data + 4, len - 4}; - bool result = OT::TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, cvar_table, + bool result = OT::TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, cvar_table, shared_indices, &iterator); assert (result); From 13900ce40da22e9c41b001e2aa1f18818094ede0 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 26 Feb 2025 13:41:52 -0700 Subject: [PATCH 3/4] [GVAR] Hook up to face and glyf table --- src/OT/glyf/Glyph.hh | 19 ++++++++++++++----- src/OT/glyf/glyf.hh | 3 +++ src/hb-ot-face-table-list.hh | 1 + src/hb-ot-var-gvar-table.hh | 4 ++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh index 42fe78394..5df44997b 100644 --- a/src/OT/glyf/Glyph.hh +++ b/src/OT/glyf/Glyph.hh @@ -386,11 +386,20 @@ struct Glyph #ifndef HB_NO_VAR if (coords) - glyf_accelerator.gvar->apply_deltas_to_points (gid, - coords, - points.as_array ().sub_array (old_length), - scratch, - phantom_only && type == SIMPLE); + { + if (glyf_accelerator.GVAR->has_data ()) + glyf_accelerator.GVAR->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + scratch, + phantom_only && type == SIMPLE); + else + glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + scratch, + phantom_only && type == SIMPLE); + } #endif // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it diff --git a/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh index c4a96bec3..d8774bea7 100644 --- a/src/OT/glyf/glyf.hh +++ b/src/OT/glyf/glyf.hh @@ -172,6 +172,7 @@ struct glyf_accelerator_t glyf_table = nullptr; #ifndef HB_NO_VAR gvar = nullptr; + GVAR = nullptr; #endif hmtx = nullptr; #ifndef HB_NO_VERTICAL @@ -187,6 +188,7 @@ struct glyf_accelerator_t glyf_table = hb_sanitize_context_t ().reference_table (face); #ifndef HB_NO_VAR gvar = face->table.gvar; + GVAR = face->table.GVAR; #endif hmtx = face->table.hmtx; #ifndef HB_NO_VERTICAL @@ -512,6 +514,7 @@ struct glyf_accelerator_t #ifndef HB_NO_VAR const gvar_accelerator_t *gvar; + const GVAR_accelerator_t *GVAR; #endif const hmtx_accelerator_t *hmtx; #ifndef HB_NO_VERTICAL diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index d52f98a78..526bea967 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -95,6 +95,7 @@ HB_OT_CORE_TABLE (OT, fvar) HB_OT_CORE_TABLE (OT, avar) HB_OT_CORE_TABLE (OT, cvar) HB_OT_ACCELERATOR (OT, gvar) +HB_OT_ACCELERATOR (OT, GVAR) HB_OT_CORE_TABLE (OT, MVAR) #ifndef HB_NO_VAR_COMPOSITES HB_OT_ACCELERATOR (OT, VARC) diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index b9f1b22db..9cd22f6d6 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -325,6 +325,8 @@ struct gvar_GVAR using GlyphVariationData = TupleVariationData; + bool has_data () const { return version.to_int () != 0; } + bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -582,6 +584,8 @@ struct gvar_GVAR public: struct accelerator_t { + bool has_data () const { return table->has_data (); } + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table (face); From 44b7ba51a3e035959fde32909d628200e2be9dc6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 26 Feb 2025 13:47:45 -0700 Subject: [PATCH 4/4] [GVAR] Hide behind HB_NO_BEYOND_64K --- src/OT/glyf/Glyph.hh | 2 ++ src/OT/glyf/glyf.hh | 6 ++++++ src/hb-ot-face-table-list.hh | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh index 5df44997b..ccd460ba0 100644 --- a/src/OT/glyf/Glyph.hh +++ b/src/OT/glyf/Glyph.hh @@ -387,6 +387,7 @@ struct Glyph #ifndef HB_NO_VAR if (coords) { +#ifndef HB_NO_BEYOND_64K if (glyf_accelerator.GVAR->has_data ()) glyf_accelerator.GVAR->apply_deltas_to_points (gid, coords, @@ -394,6 +395,7 @@ struct Glyph scratch, phantom_only && type == SIMPLE); else +#endif glyf_accelerator.gvar->apply_deltas_to_points (gid, coords, points.as_array ().sub_array (old_length), diff --git a/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh index d8774bea7..fe4ae7b8c 100644 --- a/src/OT/glyf/glyf.hh +++ b/src/OT/glyf/glyf.hh @@ -172,7 +172,9 @@ struct glyf_accelerator_t glyf_table = nullptr; #ifndef HB_NO_VAR gvar = nullptr; +#ifndef HB_NO_BEYOND_64K GVAR = nullptr; +#endif #endif hmtx = nullptr; #ifndef HB_NO_VERTICAL @@ -188,7 +190,9 @@ struct glyf_accelerator_t glyf_table = hb_sanitize_context_t ().reference_table (face); #ifndef HB_NO_VAR gvar = face->table.gvar; +#ifndef HB_NO_BEYOND_64K GVAR = face->table.GVAR; +#endif #endif hmtx = face->table.hmtx; #ifndef HB_NO_VERTICAL @@ -514,7 +518,9 @@ struct glyf_accelerator_t #ifndef HB_NO_VAR const gvar_accelerator_t *gvar; +#ifndef HB_NO_BEYOND_64K const GVAR_accelerator_t *GVAR; +#endif #endif const hmtx_accelerator_t *hmtx; #ifndef HB_NO_VERTICAL diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index 526bea967..97825f4d1 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -95,7 +95,9 @@ HB_OT_CORE_TABLE (OT, fvar) HB_OT_CORE_TABLE (OT, avar) HB_OT_CORE_TABLE (OT, cvar) HB_OT_ACCELERATOR (OT, gvar) +#ifndef HB_NO_BEYOND_64K HB_OT_ACCELERATOR (OT, GVAR) +#endif HB_OT_CORE_TABLE (OT, MVAR) #ifndef HB_NO_VAR_COMPOSITES HB_OT_ACCELERATOR (OT, VARC)