Move common structs for TupleVariation from gvar to var-common.hh
Also added a table_base in the iterator and related function to handle different start address for dataoffset in cvar and gvar
This commit is contained in:
parent
c0fac016dc
commit
22cc73f3e9
|
@ -237,6 +237,314 @@ struct VarStoreInstancer
|
||||||
hb_array_t<int> coords;
|
hb_array_t<int> coords;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
|
||||||
|
struct TupleVariationHeader
|
||||||
|
{
|
||||||
|
unsigned get_size (unsigned axis_count) const
|
||||||
|
{ return min_size + get_all_tuples (axis_count).get_size (); }
|
||||||
|
|
||||||
|
unsigned get_data_size () const { return varDataSize; }
|
||||||
|
|
||||||
|
const TupleVariationHeader &get_next (unsigned axis_count) const
|
||||||
|
{ return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
|
||||||
|
|
||||||
|
float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
|
||||||
|
const hb_array_t<const F2DOT14> shared_tuples) const
|
||||||
|
{
|
||||||
|
hb_array_t<const F2DOT14> peak_tuple;
|
||||||
|
|
||||||
|
if (has_peak ())
|
||||||
|
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.sub_array (coord_count * index, coord_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_array_t<const F2DOT14> start_tuple;
|
||||||
|
hb_array_t<const F2DOT14> end_tuple;
|
||||||
|
if (has_intermediate ())
|
||||||
|
{
|
||||||
|
start_tuple = get_start_tuple (coord_count);
|
||||||
|
end_tuple = get_end_tuple (coord_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
float scalar = 1.f;
|
||||||
|
for (unsigned int i = 0; i < coord_count; i++)
|
||||||
|
{
|
||||||
|
int v = coords[i];
|
||||||
|
int peak = peak_tuple[i].to_int ();
|
||||||
|
if (!peak || v == peak) continue;
|
||||||
|
|
||||||
|
if (has_intermediate ())
|
||||||
|
{
|
||||||
|
int start = start_tuple[i].to_int ();
|
||||||
|
int end = end_tuple[i].to_int ();
|
||||||
|
if (unlikely (start > peak || peak > end ||
|
||||||
|
(start < 0 && end > 0 && peak))) continue;
|
||||||
|
if (v < start || v > end) return 0.f;
|
||||||
|
if (v < peak)
|
||||||
|
{ if (peak != start) scalar *= (float) (v - start) / (peak - start); }
|
||||||
|
else
|
||||||
|
{ if (peak != end) scalar *= (float) (end - v) / (end - peak); }
|
||||||
|
}
|
||||||
|
else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
|
||||||
|
else
|
||||||
|
scalar *= (float) v / peak;
|
||||||
|
}
|
||||||
|
return scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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 TupleVariationData
|
||||||
|
{
|
||||||
|
const TupleVariationHeader &get_tuple_var_header (void) const
|
||||||
|
{ return StructAfter<TupleVariationHeader> (data); }
|
||||||
|
|
||||||
|
struct tuple_iterator_t
|
||||||
|
{
|
||||||
|
void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_)
|
||||||
|
{
|
||||||
|
var_data_bytes = var_data_bytes_;
|
||||||
|
var_data = var_data_bytes_.as<TupleVariationData> ();
|
||||||
|
index = 0;
|
||||||
|
axis_count = axis_count_;
|
||||||
|
current_tuple = &var_data->get_tuple_var_header ();
|
||||||
|
data_offset = 0;
|
||||||
|
table_base = table_base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
|
||||||
|
{
|
||||||
|
if (var_data->has_shared_point_numbers ())
|
||||||
|
{
|
||||||
|
const HBUINT8 *base = &(table_base+var_data->data);
|
||||||
|
const HBUINT8 *p = base;
|
||||||
|
if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
|
||||||
|
data_offset = p - base;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid () const
|
||||||
|
{
|
||||||
|
return (index < var_data->tupleVarCount.get_count ()) &&
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool move_to_next ()
|
||||||
|
{
|
||||||
|
data_offset += current_tuple->get_data_size ();
|
||||||
|
current_tuple = ¤t_tuple->get_next (axis_count);
|
||||||
|
index++;
|
||||||
|
return is_valid ();
|
||||||
|
}
|
||||||
|
|
||||||
|
const HBUINT8 *get_serialized_data () const
|
||||||
|
{ return &(table_base+var_data->data) + data_offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const TupleVariationData *var_data;
|
||||||
|
unsigned int index;
|
||||||
|
unsigned int axis_count;
|
||||||
|
unsigned int data_offset;
|
||||||
|
const void *table_base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
hb_bytes_t var_data_bytes;
|
||||||
|
const TupleVariationHeader *current_tuple;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
|
||||||
|
const void *table_base,
|
||||||
|
hb_vector_t<unsigned int> &shared_indices /* OUT */,
|
||||||
|
tuple_iterator_t *iterator /* OUT */)
|
||||||
|
{
|
||||||
|
iterator->init (var_data_bytes, axis_count, table_base);
|
||||||
|
if (!iterator->get_shared_indices (shared_indices))
|
||||||
|
return false;
|
||||||
|
return iterator->is_valid ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
|
||||||
|
|
||||||
|
static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
|
||||||
|
hb_vector_t<unsigned int> &points /* OUT */,
|
||||||
|
const HBUINT8 *end)
|
||||||
|
{
|
||||||
|
enum packed_point_flag_t
|
||||||
|
{
|
||||||
|
POINTS_ARE_WORDS = 0x80,
|
||||||
|
POINT_RUN_COUNT_MASK = 0x7F
|
||||||
|
};
|
||||||
|
|
||||||
|
if (unlikely (p + 1 > end)) return false;
|
||||||
|
|
||||||
|
unsigned count = *p++;
|
||||||
|
if (count & POINTS_ARE_WORDS)
|
||||||
|
{
|
||||||
|
if (unlikely (p + 1 > end)) return false;
|
||||||
|
count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
|
||||||
|
}
|
||||||
|
if (unlikely (!points.resize (count, false))) return false;
|
||||||
|
|
||||||
|
unsigned n = 0;
|
||||||
|
unsigned i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
if (unlikely (p + 1 > end)) return false;
|
||||||
|
unsigned control = *p++;
|
||||||
|
unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
|
||||||
|
if (unlikely (i + run_count > count)) return false;
|
||||||
|
unsigned j;
|
||||||
|
if (control & POINTS_ARE_WORDS)
|
||||||
|
{
|
||||||
|
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
|
||||||
|
for (j = 0; j < run_count; j++, i++)
|
||||||
|
{
|
||||||
|
n += *(const HBUINT16 *)p;
|
||||||
|
points.arrayZ[i] = n;
|
||||||
|
p += HBUINT16::static_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlikely (p + run_count > end)) return false;
|
||||||
|
for (j = 0; j < run_count; j++, i++)
|
||||||
|
{
|
||||||
|
n += *p++;
|
||||||
|
points.arrayZ[i] = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
|
||||||
|
hb_vector_t<int> &deltas /* IN/OUT */,
|
||||||
|
const HBUINT8 *end)
|
||||||
|
{
|
||||||
|
enum packed_delta_flag_t
|
||||||
|
{
|
||||||
|
DELTAS_ARE_ZERO = 0x80,
|
||||||
|
DELTAS_ARE_WORDS = 0x40,
|
||||||
|
DELTA_RUN_COUNT_MASK = 0x3F
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned i = 0;
|
||||||
|
unsigned count = deltas.length;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
if (unlikely (p + 1 > end)) return false;
|
||||||
|
unsigned control = *p++;
|
||||||
|
unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
|
||||||
|
if (unlikely (i + run_count > count)) return false;
|
||||||
|
unsigned j;
|
||||||
|
if (control & DELTAS_ARE_ZERO)
|
||||||
|
{
|
||||||
|
for (j = 0; j < run_count; j++, i++)
|
||||||
|
deltas.arrayZ[i] = 0;
|
||||||
|
}
|
||||||
|
else if (control & DELTAS_ARE_WORDS)
|
||||||
|
{
|
||||||
|
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
|
||||||
|
for (j = 0; j < run_count; j++, i++)
|
||||||
|
{
|
||||||
|
deltas.arrayZ[i] = * (const HBINT16 *) p;
|
||||||
|
p += HBUINT16::static_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlikely (p + run_count > end)) return false;
|
||||||
|
for (j = 0; j < run_count; j++, i++)
|
||||||
|
{
|
||||||
|
deltas.arrayZ[i] = * (const HBINT8 *) p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_data () const { return tupleVarCount; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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. */
|
||||||
|
Offset16To<HBUINT8>
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
} /* namespace OT */
|
} /* namespace OT */
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define HB_OT_VAR_GVAR_TABLE_HH
|
#define HB_OT_VAR_GVAR_TABLE_HH
|
||||||
|
|
||||||
#include "hb-open-type.hh"
|
#include "hb-open-type.hh"
|
||||||
|
#include "hb-ot-var-common.hh"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gvar -- Glyph Variation Table
|
* gvar -- Glyph Variation Table
|
||||||
|
@ -90,311 +91,8 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
|
struct GlyphVariationData : TupleVariationData
|
||||||
struct TupleVariationHeader
|
{};
|
||||||
{
|
|
||||||
unsigned get_size (unsigned axis_count) const
|
|
||||||
{ return min_size + get_all_tuples (axis_count).get_size (); }
|
|
||||||
|
|
||||||
unsigned get_data_size () const { return varDataSize; }
|
|
||||||
|
|
||||||
const TupleVariationHeader &get_next (unsigned axis_count) const
|
|
||||||
{ return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
|
|
||||||
|
|
||||||
float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
|
|
||||||
const hb_array_t<const F2DOT14> shared_tuples) const
|
|
||||||
{
|
|
||||||
hb_array_t<const F2DOT14> peak_tuple;
|
|
||||||
|
|
||||||
if (has_peak ())
|
|
||||||
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.sub_array (coord_count * index, coord_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
hb_array_t<const F2DOT14> start_tuple;
|
|
||||||
hb_array_t<const F2DOT14> end_tuple;
|
|
||||||
if (has_intermediate ())
|
|
||||||
{
|
|
||||||
start_tuple = get_start_tuple (coord_count);
|
|
||||||
end_tuple = get_end_tuple (coord_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
float scalar = 1.f;
|
|
||||||
for (unsigned int i = 0; i < coord_count; i++)
|
|
||||||
{
|
|
||||||
int v = coords[i];
|
|
||||||
int peak = peak_tuple[i].to_int ();
|
|
||||||
if (!peak || v == peak) continue;
|
|
||||||
|
|
||||||
if (has_intermediate ())
|
|
||||||
{
|
|
||||||
int start = start_tuple[i].to_int ();
|
|
||||||
int end = end_tuple[i].to_int ();
|
|
||||||
if (unlikely (start > peak || peak > end ||
|
|
||||||
(start < 0 && end > 0 && peak))) continue;
|
|
||||||
if (v < start || v > end) return 0.f;
|
|
||||||
if (v < peak)
|
|
||||||
{ if (peak != start) scalar *= (float) (v - start) / (peak - start); }
|
|
||||||
else
|
|
||||||
{ if (peak != end) scalar *= (float) (end - v) / (end - peak); }
|
|
||||||
}
|
|
||||||
else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
|
|
||||||
else
|
|
||||||
scalar *= (float) v / peak;
|
|
||||||
}
|
|
||||||
return scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
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 GlyphVariationData
|
|
||||||
{
|
|
||||||
const TupleVariationHeader &get_tuple_var_header (void) const
|
|
||||||
{ return StructAfter<TupleVariationHeader> (data); }
|
|
||||||
|
|
||||||
struct tuple_iterator_t
|
|
||||||
{
|
|
||||||
void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
|
|
||||||
{
|
|
||||||
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 ();
|
|
||||||
data_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
|
|
||||||
{
|
|
||||||
if (var_data->has_shared_point_numbers ())
|
|
||||||
{
|
|
||||||
const HBUINT8 *base = &(var_data+var_data->data);
|
|
||||||
const HBUINT8 *p = base;
|
|
||||||
if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
|
|
||||||
data_offset = p - base;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid () const
|
|
||||||
{
|
|
||||||
return (index < var_data->tupleVarCount.get_count ()) &&
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool move_to_next ()
|
|
||||||
{
|
|
||||||
data_offset += current_tuple->get_data_size ();
|
|
||||||
current_tuple = ¤t_tuple->get_next (axis_count);
|
|
||||||
index++;
|
|
||||||
return is_valid ();
|
|
||||||
}
|
|
||||||
|
|
||||||
const HBUINT8 *get_serialized_data () const
|
|
||||||
{ return &(var_data+var_data->data) + data_offset; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const GlyphVariationData *var_data;
|
|
||||||
unsigned int index;
|
|
||||||
unsigned int axis_count;
|
|
||||||
unsigned int data_offset;
|
|
||||||
|
|
||||||
public:
|
|
||||||
hb_bytes_t var_data_bytes;
|
|
||||||
const TupleVariationHeader *current_tuple;
|
|
||||||
};
|
|
||||||
|
|
||||||
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_bytes, axis_count);
|
|
||||||
if (!iterator->get_shared_indices (shared_indices))
|
|
||||||
return false;
|
|
||||||
return iterator->is_valid ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
|
|
||||||
|
|
||||||
static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
|
|
||||||
hb_vector_t<unsigned int> &points /* OUT */,
|
|
||||||
const HBUINT8 *end)
|
|
||||||
{
|
|
||||||
enum packed_point_flag_t
|
|
||||||
{
|
|
||||||
POINTS_ARE_WORDS = 0x80,
|
|
||||||
POINT_RUN_COUNT_MASK = 0x7F
|
|
||||||
};
|
|
||||||
|
|
||||||
if (unlikely (p + 1 > end)) return false;
|
|
||||||
|
|
||||||
unsigned count = *p++;
|
|
||||||
if (count & POINTS_ARE_WORDS)
|
|
||||||
{
|
|
||||||
if (unlikely (p + 1 > end)) return false;
|
|
||||||
count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
|
|
||||||
}
|
|
||||||
if (unlikely (!points.resize (count, false))) return false;
|
|
||||||
|
|
||||||
unsigned n = 0;
|
|
||||||
unsigned i = 0;
|
|
||||||
while (i < count)
|
|
||||||
{
|
|
||||||
if (unlikely (p + 1 > end)) return false;
|
|
||||||
unsigned control = *p++;
|
|
||||||
unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
|
|
||||||
if (unlikely (i + run_count > count)) return false;
|
|
||||||
unsigned j;
|
|
||||||
if (control & POINTS_ARE_WORDS)
|
|
||||||
{
|
|
||||||
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
|
|
||||||
for (j = 0; j < run_count; j++, i++)
|
|
||||||
{
|
|
||||||
n += *(const HBUINT16 *)p;
|
|
||||||
points.arrayZ[i] = n;
|
|
||||||
p += HBUINT16::static_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (unlikely (p + run_count > end)) return false;
|
|
||||||
for (j = 0; j < run_count; j++, i++)
|
|
||||||
{
|
|
||||||
n += *p++;
|
|
||||||
points.arrayZ[i] = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
|
|
||||||
hb_vector_t<int> &deltas /* IN/OUT */,
|
|
||||||
const HBUINT8 *end)
|
|
||||||
{
|
|
||||||
enum packed_delta_flag_t
|
|
||||||
{
|
|
||||||
DELTAS_ARE_ZERO = 0x80,
|
|
||||||
DELTAS_ARE_WORDS = 0x40,
|
|
||||||
DELTA_RUN_COUNT_MASK = 0x3F
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned i = 0;
|
|
||||||
unsigned count = deltas.length;
|
|
||||||
while (i < count)
|
|
||||||
{
|
|
||||||
if (unlikely (p + 1 > end)) return false;
|
|
||||||
unsigned control = *p++;
|
|
||||||
unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
|
|
||||||
if (unlikely (i + run_count > count)) return false;
|
|
||||||
unsigned j;
|
|
||||||
if (control & DELTAS_ARE_ZERO)
|
|
||||||
{
|
|
||||||
for (j = 0; j < run_count; j++, i++)
|
|
||||||
deltas.arrayZ[i] = 0;
|
|
||||||
}
|
|
||||||
else if (control & DELTAS_ARE_WORDS)
|
|
||||||
{
|
|
||||||
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
|
|
||||||
for (j = 0; j < run_count; j++, i++)
|
|
||||||
{
|
|
||||||
deltas.arrayZ[i] = * (const HBINT16 *) p;
|
|
||||||
p += HBUINT16::static_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (unlikely (p + run_count > end)) return false;
|
|
||||||
for (j = 0; j < run_count; j++, i++)
|
|
||||||
{
|
|
||||||
deltas.arrayZ[i] = * (const HBINT8 *) p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_data () const { return tupleVarCount; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
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. */
|
|
||||||
Offset16To<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);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gvar
|
struct gvar
|
||||||
{
|
{
|
||||||
|
@ -561,6 +259,7 @@ struct gvar
|
||||||
hb_vector_t<unsigned int> shared_indices;
|
hb_vector_t<unsigned int> shared_indices;
|
||||||
GlyphVariationData::tuple_iterator_t iterator;
|
GlyphVariationData::tuple_iterator_t iterator;
|
||||||
if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
|
if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
|
||||||
|
var_data_bytes.arrayZ,
|
||||||
shared_indices, &iterator))
|
shared_indices, &iterator))
|
||||||
return true; /* so isn't applied at all */
|
return true; /* so isn't applied at all */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue