#define HB_OT_VAR_GVAR_TABLE_HH
#include "hb-open-type.hh"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-var-fvar-table.hh"
/*
* gvar -- Glyph Variation Table
struct contour_point_t
{
- void init (float x_=0.f, float y_=0.f) { flag = 0; x = x_; y = y_; }
+ void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
+ { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
uint8_t flag;
float x, y;
+ bool is_end_point;
};
struct contour_point_vector_t : hb_vector_t<contour_point_t>
}
};
-struct Tuple : UnsizedArrayOf<F2DOT14> {};
-
-struct TuppleIndex : HBUINT16
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
+struct TupleVariationHeader
{
- enum Flags {
- EmbeddedPeakTuple = 0x8000u,
- IntermediateRegion = 0x4000u,
- PrivatePointNumbers = 0x2000u,
- TupleIndexMask = 0x0FFFu
- };
-
- DEFINE_SIZE_STATIC (2);
-};
+ unsigned get_size (unsigned axis_count) const
+ { return min_size + get_all_tuples (axis_count).get_size (); }
-struct TupleVarHeader
-{
- unsigned int get_size (unsigned int axis_count) const
- {
- return min_size +
- (has_peak () ? get_peak_tuple ().get_size (axis_count) : 0) +
- (has_intermediate () ? (get_start_tuple (axis_count).get_size (axis_count) +
- get_end_tuple (axis_count).get_size (axis_count)) : 0);
- }
+ unsigned get_data_size () const { return varDataSize; }
- const TupleVarHeader &get_next (unsigned int axis_count) const
- { return StructAtOffset<TupleVarHeader> (this, get_size (axis_count)); }
+ const TupleVariationHeader &get_next (unsigned axis_count) const
+ { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
float calculate_scalar (const int *coords, unsigned int coord_count,
- const hb_array_t<const F2DOT14> shared_tuples) const
+ const hb_array_t<const F2DOT14> shared_tuples) const
{
- const F2DOT14 *peak_tuple;
+ hb_array_t<const F2DOT14> peak_tuple;
if (has_peak ())
- peak_tuple = &(get_peak_tuple ()[0]);
+ peak_tuple = get_peak_tuple (coord_count);
else
{
unsigned int index = get_index ();
if (unlikely (index * coord_count >= shared_tuples.length))
return 0.f;
- peak_tuple = &shared_tuples[coord_count * index];
+ peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
}
- const F2DOT14 *start_tuple = nullptr;
- const F2DOT14 *end_tuple = nullptr;
+ hb_array_t<const F2DOT14> start_tuple;
+ hb_array_t<const F2DOT14> end_tuple;
if (has_intermediate ())
{
start_tuple = get_start_tuple (coord_count);
return scalar;
}
- unsigned int get_data_size () const { return varDataSize; }
-
bool has_peak () const { return (tupleIndex & TuppleIndex::EmbeddedPeakTuple); }
bool has_intermediate () const { return (tupleIndex & TuppleIndex::IntermediateRegion); }
bool has_private_points () const { return (tupleIndex & TuppleIndex::PrivatePointNumbers); }
unsigned int get_index () const { return (tupleIndex & TuppleIndex::TupleIndexMask); }
protected:
- const Tuple &get_peak_tuple () const
- { return StructAfter<Tuple> (tupleIndex); }
- const Tuple &get_start_tuple (unsigned int axis_count) const
- { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? axis_count : 0]; }
- const Tuple &get_end_tuple (unsigned int axis_count) const
- { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? (axis_count * 2) : axis_count]; }
-
- HBUINT16 varDataSize;
- TuppleIndex tupleIndex;
+ struct TuppleIndex : HBUINT16
+ {
+ enum Flags {
+ EmbeddedPeakTuple = 0x8000u,
+ IntermediateRegion = 0x4000u,
+ PrivatePointNumbers = 0x2000u,
+ TupleIndexMask = 0x0FFFu
+ };
+
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
+ { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
+ hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (0, axis_count); }
+ hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
+ hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
+
+ HBUINT16 varDataSize; /* The size in bytes of the serialized
+ * data for this tuple variation table. */
+ TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below).
+ The low 12 bits are an index into a shared tuple
+ records array. */
/* UnsizedArrayOf<F2DOT14> peakTuple - optional */
+ /* Peak tuple record for this tuple variation table — optional,
+ * determined by flags in the tupleIndex value.
+ *
+ * Note that this must always be included in the 'cvar' table. */
/* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
+ /* Intermediate start tuple record for this tuple variation table — optional,
+ determined by flags in the tupleIndex value. */
/* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
-
+ /* Intermediate end tuple record for this tuple variation table — optional,
+ * determined by flags in the tupleIndex value. */
public:
DEFINE_SIZE_MIN (4);
};
-struct TupleVarCount : HBUINT16
-{
- bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
- unsigned int get_count () const { return (*this) & CountMask; }
-
- protected:
- enum Flags
- {
- SharedPointNumbers = 0x8000u,
- CountMask = 0x0FFFu
- };
-
- public:
- DEFINE_SIZE_STATIC (2);
-};
-
-struct GlyphVarData
+struct GlyphVariationData
{
- const TupleVarHeader &get_tuple_var_header (void) const
- { return StructAfter<TupleVarHeader> (data); }
+ const TupleVariationHeader &get_tuple_var_header (void) const
+ { return StructAfter<TupleVariationHeader> (data); }
struct tuple_iterator_t
{
- void init (const GlyphVarData *var_data_, unsigned int length_, unsigned int axis_count_)
+ void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
{
- var_data = var_data_;
- length = length_;
+ var_data_bytes = var_data_bytes_;
+ var_data = var_data_bytes_.as<GlyphVariationData> ();
index = 0;
axis_count = axis_count_;
current_tuple = &var_data->get_tuple_var_header ();
{
if (var_data->has_shared_point_numbers ())
{
- hb_bytes_t bytes ((const char *) var_data, length);
const HBUINT8 *base = &(var_data+var_data->data);
const HBUINT8 *p = base;
- if (!unpack_points (p, shared_indices, bytes)) return false;
+ if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
data_offset = p - base;
}
return true;
bool is_valid () const
{
return (index < var_data->tupleVarCount.get_count ()) &&
- in_range (current_tuple) &&
+ var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
+ var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) &&
current_tuple->get_size (axis_count);
}
return is_valid ();
}
- bool in_range (const void *p, unsigned int l) const
- { return (const char*) p >= (const char*) var_data && (const char*) p+l <= (const char*) var_data + length; }
-
- template <typename T> bool in_range (const T *p) const { return in_range (p, sizeof (*p)); }
-
const HBUINT8 *get_serialized_data () const
{ return &(var_data+var_data->data) + data_offset; }
private:
- const GlyphVarData *var_data;
- unsigned int length;
+ const GlyphVariationData *var_data;
unsigned int index;
unsigned int axis_count;
unsigned int data_offset;
public:
- const TupleVarHeader *current_tuple;
+ hb_bytes_t var_data_bytes;
+ const TupleVariationHeader *current_tuple;
};
- static bool get_tuple_iterator (const GlyphVarData *var_data,
- unsigned int length,
- unsigned int axis_count,
- hb_vector_t<unsigned int> &shared_indices /* OUT */,
- tuple_iterator_t *iterator /* OUT */)
+ static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
+ hb_vector_t<unsigned int> &shared_indices /* OUT */,
+ tuple_iterator_t *iterator /* OUT */)
{
- iterator->init (var_data, length, axis_count);
+ iterator->init (var_data_bytes, axis_count);
if (!iterator->get_shared_indices (shared_indices))
return false;
return iterator->is_valid ();
POINT_RUN_COUNT_MASK = 0x7F
};
- if (unlikely (!bytes.in_range (p))) return false;
+ if (unlikely (!bytes.check_range (p))) return false;
uint16_t count = *p++;
if (count & POINTS_ARE_WORDS)
{
- if (unlikely (!bytes.in_range (p))) return false;
+ if (unlikely (!bytes.check_range (p))) return false;
count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
}
points.resize (count);
uint16_t i = 0;
while (i < count)
{
- if (unlikely (!bytes.in_range (p))) return false;
+ if (unlikely (!bytes.check_range (p))) return false;
uint16_t j;
uint8_t control = *p++;
uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
{
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+ if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
return false;
n += *(const HBUINT16 *)p;
points[i] = n;
{
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.in_range (p))) return false;
+ if (unlikely (!bytes.check_range (p))) return false;
n += *p++;
points[i] = n;
}
unsigned int count = deltas.length;
while (i < count)
{
- if (unlikely (!bytes.in_range (p))) return false;
+ if (unlikely (!bytes.check_range (p))) return false;
uint8_t control = *p++;
unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
unsigned int j;
else if (control & DELTAS_ARE_WORDS)
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+ if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
return false;
deltas[i] = *(const HBINT16 *) p;
p += HBUINT16::static_size;
else
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.in_range (p)))
+ if (unlikely (!bytes.check_range (p)))
return false;
deltas[i] = *(const HBINT8 *) p++;
}
return true;
}
+ bool has_data () const { return tupleVarCount; }
+
protected:
- TupleVarCount tupleVarCount;
- OffsetTo<HBUINT8> data;
- /* TupleVarHeader tupleVarHeaders[] */
+ struct TupleVarCount : HBUINT16
+ {
+ bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+ unsigned int get_count () const { return (*this) & CountMask; }
+
+ protected:
+ enum Flags
+ {
+ SharedPointNumbers= 0x8000u,
+ CountMask = 0x0FFFu
+ };
+ public:
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ TupleVarCount tupleVarCount; /* A packed field. The high 4 bits are flags, and the
+ * 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. */
+ OffsetTo<HBUINT8>
+ data; /* Offset from the start of the GlyphVariationData table
+ * to the serialized data. */
+ /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
public:
DEFINE_SIZE_MIN (4);
};
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (version.major == 1) &&
(glyphCount == c->get_num_glyphs ()) &&
- c->check_array (&(this+sharedTuples), axisCount * sharedTupleCount) &&
+ sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
(is_long_offset () ?
c->check_array (get_long_offset_array (), glyphCount+1) :
c->check_array (get_short_offset_array (), glyphCount+1)) &&
get_offset (glyphCount) - get_offset (0)));
}
- /* GlyphVarData not sanitized here; must be checked while accessing each glyph varation data */
+ /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */
bool sanitize (hb_sanitize_context_t *c) const
{ return sanitize_shallow (c); }
{
hb_codepoint_t old_gid;
if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
- subset_data_size += get_glyph_var_data_length (old_gid);
+ subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
}
bool long_offset = subset_data_size & ~0xFFFFu;
F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
if (!tuples) return_trace (false);
out->sharedTuples = (char *) tuples - (char *) out;
- memcpy (tuples, &(this+sharedTuples), shared_tuple_size);
+ memcpy (tuples, this+sharedTuples, shared_tuple_size);
}
char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
if (!subset_data) return_trace (false);
- out->dataZ = subset_data - (char *)out;
+ out->dataZ = subset_data - (char *) out;
unsigned int glyph_offset = 0;
for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
{
hb_codepoint_t old_gid;
- unsigned int length = c->plan->old_gid_for_new_gid (gid, &old_gid) ? get_glyph_var_data_length (old_gid) : 0;
+ hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
+ ? get_glyph_var_data_bytes (c->source_blob, old_gid)
+ : hb_bytes_t ();
if (long_offset)
((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
else
((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
- if (length > 0) memcpy (subset_data, get_glyph_var_data (old_gid), length);
- subset_data += length;
- glyph_offset += length;
+ if (var_data_bytes.length > 0)
+ memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+ subset_data += var_data_bytes.length;
+ glyph_offset += var_data_bytes.length;
}
if (long_offset)
((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
}
protected:
- const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
+ const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
{
- unsigned int start_offset = get_offset (glyph);
- unsigned int end_offset = get_offset (glyph+1);
-
- if ((start_offset == end_offset) ||
- unlikely ((start_offset > get_offset (glyphCount)) ||
- (start_offset + GlyphVarData::min_size > end_offset)))
- return &Null (GlyphVarData);
- return &(((unsigned char *) this + start_offset) + dataZ);
+ unsigned start_offset = get_offset (glyph);
+ unsigned length = get_offset (glyph+1) - start_offset;
+ hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
+ return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t ();
}
bool is_long_offset () const { return (flags & 1) != 0; }
return get_short_offset_array ()[i] * 2;
}
- unsigned int get_glyph_var_data_length (unsigned int glyph) const
- {
- unsigned int end_offset = get_offset (glyph + 1);
- unsigned int start_offset = get_offset (glyph);
- if (unlikely (start_offset > end_offset || end_offset > get_offset (glyphCount)))
- return 0;
- return end_offset - start_offset;
- }
-
const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
struct accelerator_t
{
void init (hb_face_t *face)
- {
- gvar_table = hb_sanitize_context_t ().reference_table<gvar> (face);
- hb_blob_ptr_t<fvar> fvar_table = hb_sanitize_context_t ().reference_table<fvar> (face);
- unsigned int axis_count = fvar_table->get_axis_count ();
- fvar_table.destroy ();
-
- if (unlikely ((gvar_table->glyphCount != face->get_num_glyphs ()) ||
- (gvar_table->axisCount != axis_count)))
- fini ();
-
- unsigned int num_shared_coord = gvar_table->sharedTupleCount * gvar_table->axisCount;
- shared_tuples.resize (num_shared_coord);
- for (unsigned int i = 0; i < num_shared_coord; i++)
- shared_tuples[i] = (&(gvar_table + gvar_table->sharedTuples))[i];
- }
-
- void fini ()
- {
- gvar_table.destroy ();
- shared_tuples.fini ();
- }
+ { table = hb_sanitize_context_t ().reference_table<gvar> (face); }
+ void fini () { table.destroy (); }
private:
struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
float next_delta = T::get (deltas[next]);
if (prev_val == next_val)
- return (prev_delta == next_delta) ? prev_delta : 0.f;
+ return (prev_delta == next_delta) ? prev_delta : 0.f;
else if (target_val <= hb_min (prev_val, next_val))
- return (prev_val < next_val) ? prev_delta : next_delta;
+ return (prev_val < next_val) ? prev_delta : next_delta;
else if (target_val >= hb_max (prev_val, next_val))
- return (prev_val > next_val) ? prev_delta : next_delta;
+ return (prev_val > next_val) ? prev_delta : next_delta;
/* linear interpolation */
float r = (target_val - prev_val) / (next_val - prev_val);
{ return (i >= end) ? start : (i + 1); }
public:
- bool apply_deltas_to_points (hb_codepoint_t glyph,
- const int *coords, unsigned int coord_count,
- const hb_array_t<contour_point_t> points,
- const hb_array_t<unsigned int> end_points) const
+ bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
+ const hb_array_t<contour_point_t> points) const
{
- if (unlikely (coord_count != gvar_table->axisCount)) return false;
+ /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */
+ if (!font->num_coords || font->num_coords != table->axisCount) return true;
- const GlyphVarData *var_data = gvar_table->get_glyph_var_data (glyph);
- if (var_data == &Null (GlyphVarData)) return true;
+ hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
+ if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
hb_vector_t<unsigned int> shared_indices;
- GlyphVarData::tuple_iterator_t iterator;
- if (!GlyphVarData::get_tuple_iterator (var_data,
- gvar_table->get_glyph_var_data_length (glyph),
- gvar_table->axisCount,
- shared_indices,
- &iterator))
- return false;
+ GlyphVariationData::tuple_iterator_t iterator;
+ if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
+ shared_indices, &iterator))
+ return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
contour_point_vector_t orig_points;
contour_point_vector_t deltas; /* flag is used to indicate referenced point */
deltas.resize (points.length);
+ hb_vector_t<unsigned> end_points;
+ for (unsigned i = 0; i < points.length; ++i)
+ if (points[i].is_end_point)
+ end_points.push (i);
+
+ int *coords = font->coords;
+ unsigned num_coords = font->num_coords;
+ hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
do
{
- float scalar = iterator.current_tuple->calculate_scalar (coords, coord_count, shared_tuples.as_array ());
+ float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
if (scalar == 0.f) continue;
const HBUINT8 *p = iterator.get_serialized_data ();
unsigned int length = iterator.current_tuple->get_data_size ();
- if (unlikely (!iterator.in_range (p, length)))
+ if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
return false;
hb_bytes_t bytes ((const char *) p, length);
hb_vector_t<unsigned int> private_indices;
if (iterator.current_tuple->has_private_points () &&
- !GlyphVarData::unpack_points (p, private_indices, bytes))
+ !GlyphVariationData::unpack_points (p, private_indices, bytes))
return false;
const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
unsigned int num_deltas = apply_to_all ? points.length : indices.length;
hb_vector_t<int> x_deltas;
x_deltas.resize (num_deltas);
- if (!GlyphVarData::unpack_deltas (p, x_deltas, bytes))
+ if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
return false;
hb_vector_t<int> y_deltas;
y_deltas.resize (num_deltas);
- if (!GlyphVarData::unpack_deltas (p, y_deltas, bytes))
+ if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
return false;
for (unsigned int i = 0; i < deltas.length; i++)
}
/* infer deltas for unreferenced points */
- unsigned int start_point = 0;
- for (unsigned int c = 0; c < end_points.length; c++)
+ unsigned start_point = 0;
+ for (unsigned c = 0; c < end_points.length; c++)
{
- unsigned int end_point = end_points[c];
- unsigned int i, j;
+ unsigned end_point = end_points[c];
/* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
- unsigned int unref_count = 0;
- for (i = start_point; i <= end_point; i++)
+ unsigned unref_count = 0;
+ for (unsigned i = start_point; i <= end_point; i++)
if (!deltas[i].flag) unref_count++;
+
+ unsigned j = start_point;
if (unref_count == 0 || unref_count > end_point - start_point)
goto no_more_gaps;
- j = start_point;
for (;;)
{
/* Locate the next gap of unreferenced points between two referenced points prev and next.
* Note that a gap may wrap around at left (start_point) and/or at right (end_point).
*/
- unsigned int prev, next;
+ unsigned int prev, next, i;
for (;;)
{
i = j;
return true;
}
- unsigned int get_axis_count () const { return gvar_table->axisCount; }
-
- protected:
- const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
- { return gvar_table->get_glyph_var_data (glyph); }
+ unsigned int get_axis_count () const { return table->axisCount; }
private:
- hb_blob_ptr_t<gvar> gvar_table;
- hb_vector_t<F2DOT14> shared_tuples;
+ hb_blob_ptr_t<gvar> table;
};
protected:
- FixedVersion<>version; /* Version of gvar table. Set to 0x00010000u. */
- HBUINT16 axisCount;
+ FixedVersion<>version; /* Version number of the glyph variations table
+ * Set to 0x00010000u. */
+ HBUINT16 axisCount; /* The number of variation axes for this font. This must be
+ * the same number as axisCount in the 'fvar' table. */
HBUINT16 sharedTupleCount;
- LOffsetTo<F2DOT14>
- sharedTuples; /* LOffsetTo<UnsizedArrayOf<Tupple>> */
- HBUINT16 glyphCount;
- HBUINT16 flags;
- LOffsetTo<GlyphVarData>
- dataZ; /* Array of GlyphVarData */
+ /* The number of shared tuple records. Shared tuple records
+ * can be referenced within glyph variation data tables for
+ * multiple glyphs, as opposed to other tuple records stored
+ * directly within a glyph variation data table. */
+ LNNOffsetTo<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 glyphCount; /* 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
+ * offsets are uint32. */
+ LOffsetTo<GlyphVariationData>
+ dataZ; /* Offset from the start of this table to the array of
+ * GlyphVariationData tables. */
UnsizedArrayOf<HBUINT8>
- offsetZ; /* Array of 16-bit or 32-bit (glyphCount+1) offsets */
+ offsetZ; /* Offsets from the start of the GlyphVariationData array
+ * to each GlyphVariationData table. */
public:
DEFINE_SIZE_MIN (20);
};