Merge pull request #4970 from harfbuzz/GVAR

Add `GVAR` table
This commit is contained in:
Behdad Esfahbod 2025-02-26 16:22:48 -07:00 committed by GitHub
commit 00541f1952
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 83 additions and 43 deletions

View file

@ -386,11 +386,22 @@ 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);
{
#ifndef HB_NO_BEYOND_64K
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
#endif
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

View file

@ -172,6 +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
@ -187,6 +190,9 @@ struct glyf_accelerator_t
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (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
@ -512,6 +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

View file

@ -95,6 +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)

View file

@ -841,6 +841,7 @@ struct tuple_delta_t
{ return (i >= end) ? start : (i + 1); }
};
template <typename OffType = HBUINT16>
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<HBUINT8>
OffsetTo<HBUINT8, OffType>
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<HBUINT16>::tuple_variations_t;
struct item_variations_t
{
using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;

View file

@ -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<unsigned> 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<int> coords,
unsigned num_cvt_item,
const TupleVariationData *tuple_var_data,
const TupleVariationData<> *tuple_var_data,
const void *base,
hb_vector_t<float>& cvt_deltas /* OUT */)
{
if (!coords) return true;
hb_vector_t<unsigned> 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<const char*> (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<unsigned int> &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);
};

View file

@ -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
{
@ -58,12 +59,13 @@ struct hb_glyf_scratch_t
namespace OT {
struct GlyphVariationData : TupleVariationData
{};
template <typename OffsetType>
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<OffsetType>::tuple_variations_t;
using GlyphVariationData = TupleVariationData<OffsetType>;
hb_vector_t<tuple_variations_t> glyph_variations;
hb_vector_t<char> compiled_shared_tuples;
@ -105,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<const GlyphVariationData*> (var_data.arrayZ);
GlyphVariationData::tuple_iterator_t iterator;
typename GlyphVariationData::tuple_iterator_t iterator;
tuple_variations_t tuple_vars;
hb_vector_t<unsigned> shared_indices;
@ -279,7 +281,7 @@ struct glyph_variations_t
hb_codepoint_t last_gid = 0;
unsigned idx = 0;
TupleVariationData* cur_glyph = c->start_embed<TupleVariationData> ();
GlyphVariationData* cur_glyph = c->start_embed<GlyphVariationData> ();
if (!cur_glyph) return_trace (false);
for (auto &_ : it)
{
@ -293,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<TupleVariationData> ();
GlyphVariationData* next_glyph = c->start_embed<GlyphVariationData> ();
glyph_offset += (char *) next_glyph - (char *) cur_glyph;
if (long_offset)
@ -316,9 +318,14 @@ struct glyph_variations_t
}
};
struct gvar
template <typename GidOffsetType, unsigned TableTag>
struct gvar_GVAR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
static constexpr hb_tag_t tableTag = TableTag;
using GlyphVariationData = TupleVariationData<GidOffsetType>;
bool has_data () const { return version.to_int () != 0; }
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
@ -337,7 +344,7 @@ struct gvar
{ return sanitize_shallow (c); }
bool decompile_glyph_variations (hb_subset_context_t *c,
glyph_variations_t& glyph_vars /* OUT */) const
glyph_variations_t<GidOffsetType>& glyph_vars /* OUT */) const
{
hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map;
auto it = hb_iter (c->plan->new_to_old_gid_list);
@ -364,14 +371,14 @@ struct gvar
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
const glyph_variations_t& glyph_vars,
const glyph_variations_t<GidOffsetType>& glyph_vars,
Iterator it,
unsigned axis_count,
unsigned num_glyphs,
bool force_long_offsets) const
{
TRACE_SERIALIZE (this);
gvar *out = c->allocate_min<gvar> ();
gvar_GVAR *out = c->allocate_min<gvar_GVAR> ();
if (unlikely (!out)) return_trace (false);
out->version.major = 1;
@ -413,7 +420,7 @@ struct gvar
bool instantiate (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
glyph_variations_t glyph_vars;
glyph_variations_t<GidOffsetType> glyph_vars;
if (!decompile_glyph_variations (c, glyph_vars))
return_trace (false);
@ -443,7 +450,7 @@ struct gvar
unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
gvar *out = c->serializer->allocate_min<gvar> ();
gvar_GVAR *out = c->serializer->allocate_min<gvar_GVAR> ();
if (unlikely (!out)) return_trace (false);
out->version.major = 1;
@ -577,9 +584,11 @@ struct 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<gvar> (face);
table = hb_sanitize_context_t ().reference_table<gvar_GVAR> (face);
/* If sanitize failed, set glyphCount to 0. */
glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
@ -658,7 +667,7 @@ struct 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))
@ -875,7 +884,7 @@ struct gvar
unsigned int get_axis_count () const { return table->axisCount; }
private:
hb_blob_ptr_t<gvar> table;
hb_blob_ptr_t<gvar_GVAR> table;
unsigned glyphCount;
hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
};
@ -893,7 +902,7 @@ struct gvar
NNOffset32To<UnsizedArrayOf<F2DOT14>>
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 +917,15 @@ struct gvar
DEFINE_SIZE_ARRAY (20, offsetZ);
};
using gvar = gvar_GVAR<HBUINT16, HB_OT_TAG_gvar>;
using GVAR = gvar_GVAR<HBUINT24, HB_OT_TAG_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 */

View file

@ -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<unsigned> shared_indices;
OT::TupleVariationData::tuple_iterator_t iterator;
OT::TupleVariationData<>::tuple_iterator_t iterator;
const OT::TupleVariationData* tuple_var_data = reinterpret_cast<const OT::TupleVariationData*> (cvar_data + 4);
const OT::TupleVariationData<>* tuple_var_data = reinterpret_cast<const OT::TupleVariationData<>*> (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);