Update HarfBuzz to 8.5.0

This commit is contained in:
bruvzg 2024-05-14 20:15:56 +03:00
parent 4971b71899
commit 7db29efa7d
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
42 changed files with 1553 additions and 526 deletions

View File

@ -377,7 +377,7 @@ Files extracted from upstream source:
## harfbuzz ## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz - Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 8.4.0 (63973005bc07aba599b47fdd4cf788647b601ccd, 2024) - Version: 8.5.0 (30485ee8c3d43c553afb9d78b9924cb71c8d2f19, 2024)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:

View File

@ -159,23 +159,35 @@ struct hb_colrv1_closure_context_t :
void add_palette_index (unsigned palette_index) void add_palette_index (unsigned palette_index)
{ palette_indices->add (palette_index); } { palette_indices->add (palette_index); }
void add_var_idxes (unsigned first_var_idx, unsigned num_idxes)
{
if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return;
variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
}
public: public:
const void *base; const void *base;
hb_set_t visited_paint; hb_set_t visited_paint;
hb_set_t *glyphs; hb_set_t *glyphs;
hb_set_t *layer_indices; hb_set_t *layer_indices;
hb_set_t *palette_indices; hb_set_t *palette_indices;
hb_set_t *variation_indices;
unsigned num_var_idxes;
unsigned nesting_level_left; unsigned nesting_level_left;
hb_colrv1_closure_context_t (const void *base_, hb_colrv1_closure_context_t (const void *base_,
hb_set_t *glyphs_, hb_set_t *glyphs_,
hb_set_t *layer_indices_, hb_set_t *layer_indices_,
hb_set_t *palette_indices_, hb_set_t *palette_indices_,
hb_set_t *variation_indices_,
unsigned num_var_idxes_ = 1,
unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
base (base_), base (base_),
glyphs (glyphs_), glyphs (glyphs_),
layer_indices (layer_indices_), layer_indices (layer_indices_),
palette_indices (palette_indices_), palette_indices (palette_indices_),
variation_indices (variation_indices_),
num_var_idxes (num_var_idxes_),
nesting_level_left (nesting_level_left_) nesting_level_left (nesting_level_left_)
{} {}
}; };
@ -242,7 +254,12 @@ struct Variable
} }
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ value.closurev1 (c); } {
c->num_var_idxes = 0;
// update c->num_var_idxes during value closure
value.closurev1 (c);
c->add_var_idxes (varIdxBase, c->num_var_idxes);
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
@ -252,8 +269,18 @@ struct Variable
if (c->plan->all_axes_pinned) if (c->plan->all_axes_pinned)
return_trace (true); return_trace (true);
//TODO: update varIdxBase for partial-instancing VarIdx new_varidx;
return_trace (c->serializer->embed (varIdxBase)); new_varidx = varIdxBase;
if (varIdxBase != VarIdx::NO_VARIATION)
{
hb_pair_t<unsigned, int> *new_varidx_delta;
if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
return_trace (false);
new_varidx = hb_first (*new_varidx_delta);
}
return_trace (c->serializer->embed (new_varidx));
} }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
@ -345,7 +372,10 @@ struct NoVariable
struct ColorStop struct ColorStop
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); } {
c->add_palette_index (paletteIndex);
c->num_var_idxes = 2;
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
@ -542,6 +572,9 @@ struct Affine2x3
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->num_var_idxes = 6; }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
@ -617,7 +650,10 @@ struct PaintColrLayers
struct PaintSolid struct PaintSolid
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); } {
c->add_palette_index (paletteIndex);
c->num_var_idxes = 1;
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
@ -666,7 +702,10 @@ template <template<typename> class Var>
struct PaintLinearGradient struct PaintLinearGradient
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } {
(this+colorLine).closurev1 (c);
c->num_var_idxes = 6;
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
@ -733,7 +772,10 @@ template <template<typename> class Var>
struct PaintRadialGradient struct PaintRadialGradient
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } {
(this+colorLine).closurev1 (c);
c->num_var_idxes = 6;
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
@ -800,7 +842,10 @@ template <template<typename> class Var>
struct PaintSweepGradient struct PaintSweepGradient
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } {
(this+colorLine).closurev1 (c);
c->num_var_idxes = 4;
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
@ -1544,6 +1589,9 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
clip_box.yMax += roundf (instancer (varIdxBase, 3)); clip_box.yMax += roundf (instancer (varIdxBase, 3));
} }
} }
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
}; };
struct ClipBox struct ClipBox
@ -1559,6 +1607,14 @@ struct ClipBox
} }
} }
void closurev1 (hb_colrv1_closure_context_t* c) const
{
switch (u.format) {
case 2: u.format2.closurev1 (c);
default:return;
}
}
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
@ -1606,6 +1662,12 @@ struct ClipRecord
int cmp (hb_codepoint_t g) const int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
{
if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return;
(base+clipBox).closurev1 (c);
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const void *base, const void *base,
const ItemVarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
@ -1941,6 +2003,76 @@ struct LayerList : Array32OfOffset32To<Paint>
} }
}; };
struct delta_set_index_map_subset_plan_t
{
unsigned get_inner_bit_count () const { return inner_bit_count; }
unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
{
map_count = 0;
outer_bit_count = 0;
inner_bit_count = 1;
output_map.init ();
/* search backwards */
unsigned count = new_deltaset_idx_varidx_map.get_population ();
if (!count) return;
unsigned last_idx = (unsigned)-1;
unsigned last_varidx = (unsigned)-1;
for (unsigned i = count; i; i--)
{
unsigned delta_set_idx = i - 1;
unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx);
if (i == count)
{
last_idx = delta_set_idx;
last_varidx = var_idx;
continue;
}
if (var_idx != last_varidx)
break;
last_idx = delta_set_idx;
}
map_count = last_idx + 1;
}
bool remap (const hb_map_t &new_deltaset_idx_varidx_map)
{
/* recalculate bit_count */
outer_bit_count = 1;
inner_bit_count = 1;
if (unlikely (!output_map.resize (map_count, false))) return false;
for (unsigned idx = 0; idx < map_count; idx++)
{
uint32_t *var_idx;
if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false;
output_map.arrayZ[idx] = *var_idx;
unsigned outer = (*var_idx) >> 16;
unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
outer_bit_count = hb_max (bit_count, outer_bit_count);
unsigned inner = (*var_idx) & 0xFFFF;
bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
inner_bit_count = hb_max (bit_count, inner_bit_count);
}
return true;
}
private:
unsigned map_count;
unsigned outer_bit_count;
unsigned inner_bit_count;
hb_vector_t<uint32_t> output_map;
};
struct COLR struct COLR
{ {
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@ -1992,8 +2124,22 @@ struct COLR
void closure_forV1 (hb_set_t *glyphset, void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices, hb_set_t *layer_indices,
hb_set_t *palette_indices) const hb_set_t *palette_indices,
{ colr->closure_forV1 (glyphset, layer_indices, palette_indices); } hb_set_t *variation_indices,
hb_set_t *delta_set_indices) const
{ colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); }
bool has_var_store () const
{ return colr->has_var_store (); }
const ItemVariationStore &get_var_store () const
{ return colr->get_var_store (); }
bool has_delta_set_index_map () const
{ return colr->has_delta_set_index_map (); }
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return colr->get_delta_set_index_map (); }
private: private:
hb_blob_ptr_t<COLR> colr; hb_blob_ptr_t<COLR> colr;
@ -2030,14 +2176,16 @@ struct COLR
void closure_forV1 (hb_set_t *glyphset, void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices, hb_set_t *layer_indices,
hb_set_t *palette_indices) const hb_set_t *palette_indices,
hb_set_t *variation_indices,
hb_set_t *delta_set_indices) const
{ {
if (version != 1) return; if (version != 1) return;
hb_barrier (); hb_barrier ();
hb_set_t visited_glyphs; hb_set_t visited_glyphs;
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices);
const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
@ -2049,6 +2197,22 @@ struct COLR
paint.dispatch (&c); paint.dispatch (&c);
} }
hb_set_union (glyphset, &visited_glyphs); hb_set_union (glyphset, &visited_glyphs);
const ClipList &cliplist = this+clipList;
c.glyphs = glyphset;
for (const ClipRecord &clip_record : cliplist.clips.iter())
clip_record.closurev1 (&c, &cliplist);
// if a DeltaSetIndexMap is included, collected variation indices are
// actually delta set indices, we need to map them into variation indices
if (has_delta_set_index_map ())
{
const DeltaSetIndexMap &var_idx_map = this+varIdxMap;
delta_set_indices->set (*variation_indices);
variation_indices->clear ();
for (unsigned delta_set_idx : *delta_set_indices)
variation_indices->add (var_idx_map.map (delta_set_idx));
}
} }
const LayerList& get_layerList () const const LayerList& get_layerList () const
@ -2057,6 +2221,18 @@ struct COLR
const BaseGlyphList& get_baseglyphList () const const BaseGlyphList& get_baseglyphList () const
{ return (this+baseGlyphList); } { return (this+baseGlyphList); }
bool has_var_store () const
{ return version >= 1 && varStore != 0; }
bool has_delta_set_index_map () const
{ return version >= 1 && varIdxMap != 0; }
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return (version == 0 || varIdxMap == 0) ? Null (DeltaSetIndexMap) : this+varIdxMap; }
const ItemVariationStore &get_var_store () const
{ return (version == 0 || varStore == 0) ? Null (ItemVariationStore) : this+varStore; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -2132,6 +2308,88 @@ struct COLR
return record; return record;
} }
bool downgrade_to_V0 (const hb_set_t &glyphset) const
{
//no more COLRv1 glyphs, downgrade to version 0
for (const BaseGlyphPaintRecord& _ : get_baseglyphList ())
if (glyphset.has (_.glyphId))
return false;
return true;
}
bool subset_varstore (hb_subset_context_t *c,
COLR* out /* OUT */) const
{
TRACE_SUBSET (this);
if (!varStore || c->plan->all_axes_pinned ||
!c->plan->colrv1_variation_idx_delta_map)
return_trace (true);
const ItemVariationStore& var_store = this+varStore;
if (c->plan->normalized_coords)
{
item_variations_t item_vars;
/* turn off varstore optimization when varIdxMap is null, so we maintain
* original var_idx sequence */
bool optimize = (varIdxMap != 0) ? true : false;
if (!item_vars.instantiate (var_store, c->plan,
optimize, /* optimization */
optimize, /* use_no_variation_idx = false */
c->plan->colrv1_varstore_inner_maps.as_array ()))
return_trace (false);
if (!out->varStore.serialize_serialize (c->serializer,
item_vars.has_long_word (),
c->plan->axis_tags,
item_vars.get_region_list (),
item_vars.get_vardata_encodings ()))
return_trace (false);
/* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
* subset plan */
if (optimize)
{
const hb_map_t &varidx_map = item_vars.get_varidx_map ();
for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ())
{
uint32_t varidx = _.second;
uint32_t *new_varidx;
if (varidx_map.has (varidx, &new_varidx))
_.second = *new_varidx;
else
_.second = VarIdx::NO_VARIATION;
}
}
}
else
{
if (unlikely (!out->varStore.serialize_serialize (c->serializer,
&var_store,
c->plan->colrv1_varstore_inner_maps.as_array ())))
return_trace (false);
}
return_trace (true);
}
bool subset_delta_set_index_map (hb_subset_context_t *c,
COLR* out /* OUT */) const
{
TRACE_SUBSET (this);
if (!varIdxMap || c->plan->all_axes_pinned ||
!c->plan->colrv1_new_deltaset_idx_varidx_map)
return_trace (true);
const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map;
delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map);
if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map)))
return_trace (false);
return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan));
}
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -2200,34 +2458,28 @@ struct COLR
auto *colr_prime = c->serializer->start_embed<COLR> (); auto *colr_prime = c->serializer->start_embed<COLR> ();
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
if (version == 0) if (version == 0 || downgrade_to_V0 (glyphset))
return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)); return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
auto snap = c->serializer->snapshot (); //start version 1
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
/* subset ItemVariationStore first, cause varidx_map needs to be updated
* after instancing */
if (!subset_varstore (c, colr_prime)) return_trace (false);
ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr, ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr, varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ()); c->plan->normalized_coords.as_array ());
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
{ return_trace (false);
if (c->serializer->in_error ()) return_trace (false);
//no more COLRv1 glyphs: downgrade to version 0
c->serializer->revert (snap);
return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
}
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
colr_prime->layerList.serialize_subset (c, layerList, this, instancer); colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
colr_prime->clipList.serialize_subset (c, clipList, this, instancer); colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
if (!varStore || c->plan->all_axes_pinned)
return_trace (true);
colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); return_trace (subset_delta_set_index_map (c, colr_prime));
colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
return_trace (true);
} }
const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const

View File

@ -66,34 +66,64 @@ HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) cons
template <template<typename> class Var> template <template<typename> class Var>
HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
(this+transform).closurev1 (c);
}
HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 2;
}
HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 2;
}
HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 4;
}
HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 1;
}
HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 3;
}
HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 1;
}
HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 3;
}
HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 2;
}
HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); } {
(this+src).dispatch (c);
c->num_var_idxes = 4;
}
HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
{ {

View File

@ -1022,47 +1022,6 @@ struct GDEF
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); } { get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
const hb_vector_t<int>& normalized_coords,
bool calculate_delta, /* not pinned at default */
bool no_variations, /* all axes pinned */
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
const ItemVariationStore &var_store = get_var_store ();
float *store_cache = var_store.create_cache ();
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
{
int delta = 0;
if (calculate_delta)
delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
normalized_coords.length, store_cache));
if (no_variations)
{
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
continue;
}
uint16_t major = idx >> 16;
if (major >= var_store.get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
var_store.destroy_cache (store_cache);
}
protected: protected:
union { union {
FixedVersion<> version; /* Version identifier */ FixedVersion<> version; /* Version identifier */

View File

@ -90,8 +90,17 @@ struct Ligature
unsigned int total_component_count = 0; unsigned int total_component_count = 0;
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
if (unlikely (!match_positions))
return_trace (false);
}
unsigned int match_end = 0; unsigned int match_end = 0;
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count, if (likely (!match_input (c, count,
&component[1], &component[1],
@ -102,6 +111,8 @@ struct Ligature
&total_component_count))) &total_component_count)))
{ {
c->buffer->unsafe_to_concat (c->buffer->idx, match_end); c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (false); return_trace (false);
} }
@ -145,6 +156,8 @@ struct Ligature
pos); pos);
} }
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (true); return_trace (true);
} }

View File

@ -46,8 +46,9 @@ struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{ {
const char *get_name () { return "APPLY"; } const char *get_name () { return "APPLY"; }
template <typename T> template <typename T, typename ...Ts>
return_t dispatch (const T &obj) { return obj.apply (this); } return_t dispatch (const T &obj, Ts&&... ds)
{ return obj.apply (this, std::forward<Ts> (ds)...); }
static return_t default_return_value () { return false; } static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; } bool stop_sublookup_iteration (return_t r) const { return r; }
@ -59,6 +60,9 @@ struct hb_aat_apply_context_t :
const ankr *ankr_table; const ankr *ankr_table;
const OT::GDEF *gdef_table; const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr; const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
hb_set_digest_t left_set = hb_set_digest_t::full ();
hb_set_digest_t right_set = hb_set_digest_t::full ();
hb_mask_t subtable_flags = 0; hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */ /* Unused. For debug tracing only. */
@ -81,6 +85,8 @@ struct hb_aat_apply_context_t :
* Lookup Table * Lookup Table
*/ */
enum { DELETED_GLYPH = 0xFFFF };
template <typename T> struct Lookup; template <typename T> struct Lookup;
template <typename T> template <typename T>
@ -95,6 +101,12 @@ struct LookupFormat0
return &arrayZ[glyph_id]; return &arrayZ[glyph_id];
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
glyphs.add_range (0, num_glyphs - 1);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -123,6 +135,14 @@ struct LookupSegmentSingle
int cmp (hb_codepoint_t g) const int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1 ; } { return g < first ? -1 : g <= last ? 0 : +1 ; }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH)
return;
glyphs.add_range (first, last);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -153,6 +173,14 @@ struct LookupFormat2
return v ? &v->value : nullptr; return v ? &v->value : nullptr;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
unsigned count = segments.get_length ();
for (unsigned int i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -184,6 +212,14 @@ struct LookupSegmentArray
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH)
return;
glyphs.add_range (first, last);
}
int cmp (hb_codepoint_t g) const int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; } { return g < first ? -1 : g <= last ? 0 : +1; }
@ -226,6 +262,14 @@ struct LookupFormat4
return v ? v->get_value (glyph_id, this) : nullptr; return v ? v->get_value (glyph_id, this) : nullptr;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
unsigned count = segments.get_length ();
for (unsigned i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -254,6 +298,14 @@ struct LookupSingle
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (glyph == DELETED_GLYPH)
return;
glyphs.add (glyph);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -283,6 +335,14 @@ struct LookupFormat6
return v ? &v->value : nullptr; return v ? &v->value : nullptr;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
unsigned count = entries.get_length ();
for (unsigned i = 0; i < count; i++)
entries[i].collect_glyphs (glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -314,6 +374,16 @@ struct LookupFormat8
&valueArrayZ[glyph_id - firstGlyph] : nullptr; &valueArrayZ[glyph_id - firstGlyph] : nullptr;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -358,6 +428,16 @@ struct LookupFormat10
return v; return v;
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -406,6 +486,20 @@ struct Lookup
} }
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
{
switch (u.format) {
case 0: u.format0.collect_glyphs (glyphs, num_glyphs); return;
case 2: u.format2.collect_glyphs (glyphs); return;
case 4: u.format4.collect_glyphs (glyphs); return;
case 6: u.format6.collect_glyphs (glyphs); return;
case 8: u.format8.collect_glyphs (glyphs); return;
case 10: u.format10.collect_glyphs (glyphs); return;
default:return;
}
}
typename T::type get_class (hb_codepoint_t glyph_id, typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs, unsigned int num_glyphs,
unsigned int outOfRange) const unsigned int outOfRange) const
@ -460,8 +554,6 @@ struct Lookup
}; };
DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
enum { DELETED_GLYPH = 0xFFFF };
/* /*
* (Extended) State Table * (Extended) State Table
*/ */
@ -512,6 +604,14 @@ struct Entry<void>
DEFINE_SIZE_STATIC (4); DEFINE_SIZE_STATIC (4);
}; };
enum Class
{
CLASS_END_OF_TEXT = 0,
CLASS_OUT_OF_BOUNDS = 1,
CLASS_DELETED_GLYPH = 2,
CLASS_END_OF_LINE = 3,
};
template <typename Types, typename Extra> template <typename Types, typename Extra>
struct StateTable struct StateTable
{ {
@ -524,21 +624,24 @@ struct StateTable
STATE_START_OF_TEXT = 0, STATE_START_OF_TEXT = 0,
STATE_START_OF_LINE = 1, STATE_START_OF_LINE = 1,
}; };
enum Class
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{ {
CLASS_END_OF_TEXT = 0, (this+classTable).collect_glyphs (glyphs, num_glyphs);
CLASS_OUT_OF_BOUNDS = 1, }
CLASS_DELETED_GLYPH = 2,
CLASS_END_OF_LINE = 3,
};
int new_state (unsigned int newState) const int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const template <typename set_t>
unsigned int get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
const set_t &glyphs) const
{ {
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
return (this+classTable).get_class (glyph_id, num_glyphs, 1); if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
} }
const Entry<Extra> *get_entries () const const Entry<Extra> *get_entries () const
@ -547,7 +650,7 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const const Entry<Extra> &get_entry (int state, unsigned int klass) const
{ {
if (unlikely (klass >= nClasses)) if (unlikely (klass >= nClasses))
klass = StateTable::CLASS_OUT_OF_BOUNDS; klass = CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ; const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ; const Entry<Extra> *entries = (this+entryTable).arrayZ;
@ -690,6 +793,15 @@ struct ClassTable
{ {
return get_class (glyph_id, outOfRange); return get_class (glyph_id, outOfRange);
} }
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
for (unsigned i = 0; i < classArray.len; i++)
if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
glyphs.add (firstGlyph + i);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -703,6 +815,38 @@ struct ClassTable
DEFINE_SIZE_ARRAY (4, classArray); DEFINE_SIZE_ARRAY (4, classArray);
}; };
struct SubtableGlyphCoverage
{
bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_array (&subtableOffsets, subtable_count)))
return_trace (false);
unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT;
for (unsigned i = 0; i < subtable_count; i++)
{
uint32_t offset = (uint32_t) subtableOffsets[i];
if (offset == 0 || offset == 0xFFFFFFFF)
continue;
if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
return_trace (false);
}
return_trace (true);
}
protected:
UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets;
/* Array of offsets from the beginning of the
* subtable glyph coverage table to the glyph
* coverage bitfield for a given subtable; there
* is one offset for each subtable in the chain */
/* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
public:
DEFINE_SIZE_ARRAY (0, subtableOffsets);
};
struct ObsoleteTypes struct ObsoleteTypes
{ {
static constexpr bool extended = false; static constexpr bool extended = false;
@ -779,15 +923,15 @@ struct StateTableDriver
using EntryT = Entry<EntryData>; using EntryT = Entry<EntryData>;
StateTableDriver (const StateTableT &machine_, StateTableDriver (const StateTableT &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) : hb_face_t *face_) :
machine (machine_), machine (machine_),
buffer (buffer_),
num_glyphs (face_->get_num_glyphs ()) {} num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t> template <typename context_t, typename set_t = hb_set_digest_t>
void drive (context_t *c, hb_aat_apply_context_t *ac) void drive (context_t *c, hb_aat_apply_context_t *ac)
{ {
hb_buffer_t *buffer = ac->buffer;
if (!c->in_place) if (!c->in_place)
buffer->clear_output (); buffer->clear_output ();
@ -822,9 +966,9 @@ struct StateTableDriver
} }
} }
unsigned int klass = buffer->idx < buffer->len ? unsigned int klass = likely (buffer->idx < buffer->len) ?
machine.get_class (buffer->cur().codepoint, num_glyphs) : machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
(unsigned) StateTableT::CLASS_END_OF_TEXT; (unsigned) CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const EntryT &entry = machine.get_entry (state, klass); const EntryT &entry = machine.get_entry (state, klass);
const int next_state = machine.new_state (entry.newState); const int next_state = machine.new_state (entry.newState);
@ -862,22 +1006,22 @@ struct StateTableDriver
{ {
/* 2c. */ /* 2c. */
const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass); const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
/* 2c'. */ /* 2c'. */
if (c->is_actionable (this, wouldbe_entry)) if (c->is_actionable (buffer, this, wouldbe_entry))
return false; return false;
/* 2c". */ /* 2c". */
return next_state == machine.new_state(wouldbe_entry.newState) return next_state == machine.new_state(wouldbe_entry.newState)
&& (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance); && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
}; };
const auto is_safe_to_break = [&]() const auto is_safe_to_break = [&]()
{ {
/* 1. */ /* 1. */
if (c->is_actionable (this, entry)) if (c->is_actionable (buffer, this, entry))
return false; return false;
/* 2. */ /* 2. */
// This one is meh, I know... // This one is meh, I know...
const auto ok = const auto ok =
@ -886,15 +1030,15 @@ struct StateTableDriver
|| is_safe_to_break_extra(); || is_safe_to_break_extra();
if (!ok) if (!ok)
return false; return false;
/* 3. */ /* 3. */
return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT)); return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
}; };
if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (this, entry); c->transition (buffer, this, entry);
state = next_state; state = next_state;
DEBUG_MSG (APPLY, nullptr, "s%d", state); DEBUG_MSG (APPLY, nullptr, "s%d", state);
@ -912,7 +1056,6 @@ struct StateTableDriver
public: public:
const StateTableT &machine; const StateTableT &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs; unsigned int num_glyphs;
}; };

View File

@ -30,6 +30,7 @@
#include "hb-kern.hh" #include "hb-kern.hh"
#include "hb-aat-layout-ankr-table.hh" #include "hb-aat-layout-ankr-table.hh"
#include "hb-set-digest.hh"
/* /*
* kerx -- Extended Kerning * kerx -- Extended Kerning
@ -82,7 +83,7 @@ struct KernPair
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
protected: public:
HBGlyphID16 left; HBGlyphID16 left;
HBGlyphID16 right; HBGlyphID16 right;
FWORD value; FWORD value;
@ -118,6 +119,16 @@ struct KerxSubTableFormat0
return_trace (true); return_trace (true);
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
for (const KernPair& pair : pairs)
{
left_set.add (pair.left);
right_set.add (pair.right);
}
}
struct accelerator_t struct accelerator_t
{ {
const KerxSubTableFormat0 &table; const KerxSubTableFormat0 &table;
@ -128,7 +139,10 @@ struct KerxSubTableFormat0
table (table_), c (c_) {} table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); } {
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
}; };
@ -228,13 +242,14 @@ struct KerxSubTableFormat1
depth (0), depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {} crossStream (table->header.coverage & table->header.CrossStream) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ return Format1EntryT::performAction (entry); } { return Format1EntryT::performAction (entry); }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags; unsigned int flags = entry.flags;
if (flags & Format1EntryT::Reset) if (flags & Format1EntryT::Reset)
@ -351,7 +366,7 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); StateTableDriver<Types, EntryData> driver (machine, c->font->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (true); return_trace (true);
@ -365,12 +380,21 @@ struct KerxSubTableFormat1
machine.sanitize (c))); machine.sanitize (c)));
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
}
protected: protected:
KernSubTableHeader header; KernSubTableHeader header;
StateTable<Types, EntryData> machine; StateTable<Types, EntryData> machine;
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction; NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
public: public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT)); DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
}; };
template <typename KernSubTableHeader> template <typename KernSubTableHeader>
@ -413,6 +437,13 @@ struct KerxSubTableFormat2
return_trace (true); return_trace (true);
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
(this+leftClassTable).collect_glyphs (left_set, num_glyphs);
(this+rightClassTable).collect_glyphs (right_set, num_glyphs);
}
struct accelerator_t struct accelerator_t
{ {
const KerxSubTableFormat2 &table; const KerxSubTableFormat2 &table;
@ -423,7 +454,10 @@ struct KerxSubTableFormat2
table (table_), c (c_) {} table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); } {
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
}; };
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
@ -493,14 +527,14 @@ struct KerxSubTableFormat4
mark_set (false), mark_set (false),
mark (0) {} mark (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ return entry.data.ankrActionIndex != 0xFFFF; } { return entry.data.ankrActionIndex != 0xFFFF; }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
{ {
hb_glyph_position_t &o = buffer->cur_pos(); hb_glyph_position_t &o = buffer->cur_pos();
@ -600,7 +634,7 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); StateTableDriver<Types, EntryData> driver (machine, c->font->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (true); return_trace (true);
@ -614,12 +648,21 @@ struct KerxSubTableFormat4
machine.sanitize (c))); machine.sanitize (c)));
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
}
protected: protected:
KernSubTableHeader header; KernSubTableHeader header;
StateTable<Types, EntryData> machine; StateTable<Types, EntryData> machine;
HBUINT32 flags; HBUINT32 flags;
public: public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20); DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
}; };
template <typename KernSubTableHeader> template <typename KernSubTableHeader>
@ -638,7 +681,7 @@ struct KerxSubTableFormat6
unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
if (is_long ()) if (is_long ())
{ {
const typename U::Long &t = u.l; const auto &t = u.l;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r; unsigned int offset = l + r;
@ -651,7 +694,7 @@ struct KerxSubTableFormat6
} }
else else
{ {
const typename U::Short &t = u.s; const auto &t = u.s;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r; unsigned int offset = l + r;
@ -698,6 +741,23 @@ struct KerxSubTableFormat6
c->check_range (this, vector)))); c->check_range (this, vector))));
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
if (is_long ())
{
const auto &t = u.l;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
}
else
{
const auto &t = u.s;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
}
}
struct accelerator_t struct accelerator_t
{ {
const KerxSubTableFormat6 &table; const KerxSubTableFormat6 &table;
@ -708,7 +768,10 @@ struct KerxSubTableFormat6
table (table_), c (c_) {} table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); } {
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
}; };
protected: protected:
@ -794,6 +857,20 @@ struct KerxSubTable
} }
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
unsigned int subtable_type = get_type ();
switch (subtable_type) {
case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
default: return;
}
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -824,6 +901,8 @@ struct KerxSubTable
* The 'kerx' Table * The 'kerx' Table
*/ */
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
template <typename T> template <typename T>
struct KerxTable struct KerxTable
{ {
@ -878,7 +957,8 @@ struct KerxTable
return v; return v;
} }
bool apply (AAT::hb_aat_apply_context_t *c) const bool apply (AAT::hb_aat_apply_context_t *c,
const kern_accelerator_data_t *accel_data = nullptr) const
{ {
c->buffer->unsafe_to_concat (); c->buffer->unsafe_to_concat ();
@ -925,6 +1005,16 @@ struct KerxTable
if (reverse) if (reverse)
c->buffer->reverse (); c->buffer->reverse ();
if (accel_data)
{
c->left_set = (*accel_data)[i].first;
c->right_set = (*accel_data)[i].second;
}
else
{
c->left_set = c->right_set = hb_set_digest_t::full ();
}
{ {
/* See comment in sanitize() for conditional here. */ /* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@ -977,8 +1067,61 @@ struct KerxTable
st = &StructAfter<SubTable> (*st); st = &StructAfter<SubTable> (*st);
} }
unsigned majorVersion = thiz()->version;
if (sizeof (thiz()->version) == 4)
majorVersion = majorVersion >> 16;
if (majorVersion >= 3)
{
const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
if (!coverage->sanitize (c, count))
return_trace (false);
}
return_trace (true); return_trace (true);
} }
kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
{
kern_accelerator_data_t accel_data;
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
hb_set_digest_t left_set, right_set;
st->collect_glyphs (left_set, right_set, num_glyphs);
accel_data.push (hb_pair (left_set, right_set));
st = &StructAfter<SubTable> (*st);
}
return accel_data;
}
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
hb_sanitize_context_t sc;
this->table = sc.reference_table<T> (face);
this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
}
~accelerator_t ()
{
this->table.destroy ();
}
hb_blob_t *get_blob () const { return table.get_blob (); }
bool apply (AAT::hb_aat_apply_context_t *c) const
{
return table->apply (c, &accel_data);
}
hb_blob_ptr_t<T> table;
kern_accelerator_data_t accel_data;
};
}; };
struct kerx : KerxTable<kerx> struct kerx : KerxTable<kerx>
@ -1007,8 +1150,10 @@ struct kerx : KerxTable<kerx>
DEFINE_SIZE_MIN (8); DEFINE_SIZE_MIN (8);
}; };
struct kerx_accelerator_t : kerx::accelerator_t {
kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {}
};
} /* namespace AAT */ } /* namespace AAT */
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */ #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */

View File

@ -74,15 +74,16 @@ struct RearrangementSubtable
ret (false), ret (false),
start (0), end (0) {} start (0), end (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
const Entry<EntryData> &entry) StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{ {
return (entry.flags & Verb) && start < end; return (entry.flags & Verb) && start < end;
} }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags; unsigned int flags = entry.flags;
if (flags & MarkFirst) if (flags & MarkFirst)
@ -168,7 +169,7 @@ struct RearrangementSubtable
driver_context_t dc (this); driver_context_t dc (this);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
@ -180,10 +181,10 @@ struct RearrangementSubtable
return_trace (machine.sanitize (c)); return_trace (machine.sanitize (c));
} }
protected: public:
StateTable<Types, EntryData> machine; StateTable<Types, EntryData> machine;
public: public:
DEFINE_SIZE_STATIC (16); DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
}; };
template <typename Types> template <typename Types>
@ -223,21 +224,19 @@ struct ContextualSubtable
table (table_), table (table_),
subs (table+table->substitutionTables) {} subs (table+table->substitutionTables) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver, bool is_actionable (hb_buffer_t *buffer,
const Entry<EntryData> &entry) StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const
{ {
hb_buffer_t *buffer = driver->buffer;
if (buffer->idx == buffer->len && !mark_set) if (buffer->idx == buffer->len && !mark_set)
return false; return false;
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
} }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
/* Looks like CoreText applies neither mark nor current substitution for /* Looks like CoreText applies neither mark nor current substitution for
* end-of-text if mark was not explicitly set. */ * end-of-text if mark was not explicitly set. */
if (buffer->idx == buffer->len && !mark_set) if (buffer->idx == buffer->len && !mark_set)
@ -328,7 +327,7 @@ struct ContextualSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
@ -361,13 +360,14 @@ struct ContextualSubtable
return_trace (substitutionTables.sanitize (c, this, num_lookups)); return_trace (substitutionTables.sanitize (c, this, num_lookups));
} }
protected: public:
StateTable<Types, EntryData> StateTable<Types, EntryData>
machine; machine;
protected:
NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT> NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
substitutionTables; substitutionTables;
public: public:
DEFINE_SIZE_STATIC (20); DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
}; };
@ -464,16 +464,16 @@ struct LigatureSubtable
ligature (table+table->ligature), ligature (table+table->ligature),
match_length (0) {} match_length (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
const Entry<EntryData> &entry) StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{ {
return LigatureEntryT::performAction (entry); return LigatureEntryT::performAction (entry);
} }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
if (entry.flags & LigatureEntryT::SetComponent) if (entry.flags & LigatureEntryT::SetComponent)
{ {
@ -585,7 +585,7 @@ struct LigatureSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
@ -600,9 +600,10 @@ struct LigatureSubtable
ligAction && component && ligature); ligAction && component && ligature);
} }
protected: public:
StateTable<Types, EntryData> StateTable<Types, EntryData>
machine; machine;
protected:
NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT> NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
ligAction; /* Offset to the ligature action table. */ ligAction; /* Offset to the ligature action table. */
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT> NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
@ -610,7 +611,7 @@ struct LigatureSubtable
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
ligature; /* Offset to the actual ligature lists. */ ligature; /* Offset to the actual ligature lists. */
public: public:
DEFINE_SIZE_STATIC (28); DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
}; };
template <typename Types> template <typename Types>
@ -754,16 +755,17 @@ struct InsertionSubtable
mark (0), mark (0),
insertionAction (table+table->insertionAction) {} insertionAction (table+table->insertionAction) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
const Entry<EntryData> &entry) StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{ {
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
} }
void transition (StateTableDriver<Types, EntryData> *driver, void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const Entry<EntryData> &entry)
{ {
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags; unsigned int flags = entry.flags;
unsigned mark_loc = buffer->out_len; unsigned mark_loc = buffer->out_len;
@ -850,7 +852,7 @@ struct InsertionSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
@ -865,14 +867,15 @@ struct InsertionSubtable
insertionAction); insertionAction);
} }
protected: public:
StateTable<Types, EntryData> StateTable<Types, EntryData>
machine; machine;
protected:
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
insertionAction; /* Byte offset from stateHeader to the start of insertionAction; /* Byte offset from stateHeader to the start of
* the insertion glyph table. */ * the insertion glyph table. */
public: public:
DEFINE_SIZE_STATIC (20); DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
}; };
@ -896,6 +899,89 @@ struct Feature
DEFINE_SIZE_STATIC (12); DEFINE_SIZE_STATIC (12);
}; };
struct hb_accelerate_subtables_context_t :
hb_dispatch_context_t<hb_accelerate_subtables_context_t>
{
struct hb_applicable_t
{
friend struct hb_accelerate_subtables_context_t;
friend struct hb_aat_layout_lookup_accelerator_t;
public:
hb_set_digest_t digest;
template <typename T>
auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
(
obj_.machine.collect_glyphs (this->digest, num_glyphs)
)
template <typename T>
void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
{
digest = digest.full ();
}
template <typename T>
void init (const T &obj_, unsigned num_glyphs)
{
init_ (obj_, num_glyphs, hb_prioritize);
}
};
/* Dispatch interface. */
template <typename T>
return_t dispatch (const T &obj)
{
hb_applicable_t *entry = &array[i++];
entry->init (obj, num_glyphs);
return hb_empty_t ();
}
static return_t default_return_value () { return hb_empty_t (); }
bool stop_sublookup_iteration (return_t r) const { return false; }
hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
array (array_), num_glyphs (num_glyphs_) {}
hb_applicable_t *array;
unsigned num_glyphs;
unsigned i = 0;
};
struct hb_aat_layout_chain_accelerator_t
{
template <typename TChain>
static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
{
unsigned count = chain.get_subtable_count ();
unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) -
HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
/* The following is a calloc because when we are collecting subtables,
* some of them might be invalid and hence not collect; as a result,
* we might not fill in all the count entries of the subtables array.
* Zeroing it allows the set digest to gatekeep it without having to
* initialize it further. */
auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
if (unlikely (!thiz))
return nullptr;
hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
chain.dispatch (&c_accelerate_subtables);
return thiz;
}
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
};
template <typename Types> template <typename Types>
struct ChainSubtable struct ChainSubtable
{ {
@ -987,6 +1073,8 @@ struct Chain
{ {
typedef typename Types::HBUINT HBUINT; typedef typename Types::HBUINT HBUINT;
unsigned get_subtable_count () const { return subtableCount; }
hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
{ {
hb_mask_t flags = defaultFlags; hb_mask_t flags = defaultFlags;
@ -1027,7 +1115,8 @@ struct Chain
return flags; return flags;
} }
void apply (hb_aat_apply_context_t *c) const void apply (hb_aat_apply_context_t *c,
const hb_aat_layout_chain_accelerator_t *accel) const
{ {
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
unsigned int count = subtableCount; unsigned int count = subtableCount;
@ -1039,6 +1128,7 @@ struct Chain
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
goto skip; goto skip;
c->subtable_flags = subtable->subFeatureFlags; c->subtable_flags = subtable->subFeatureFlags;
c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@ -1100,7 +1190,22 @@ struct Chain
unsigned int get_size () const { return length; } unsigned int get_size () const { return length; }
bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
if (c->stop_sublookup_iteration (ret))
return ret;
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
}
return c->default_return_value ();
}
bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!(length.sanitize (c) && if (!(length.sanitize (c) &&
@ -1122,6 +1227,13 @@ struct Chain
subtable = &StructAfter<ChainSubtable<Types>> (*subtable); subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
} }
if (version >= 3)
{
const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
if (!coverage->sanitize (c, count))
return_trace (false);
}
return_trace (true); return_trace (true);
} }
@ -1133,7 +1245,7 @@ struct Chain
UnsizedArrayOf<Feature> featureZ; /* Features. */ UnsizedArrayOf<Feature> featureZ; /* Features. */
/*ChainSubtable firstSubtable;*//* Subtables. */ /*ChainSubtable firstSubtable;*//* Subtables. */
/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
public: public:
DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
@ -1144,13 +1256,69 @@ struct Chain
* The 'mort'/'morx' Table * The 'mort'/'morx' Table
*/ */
template <typename Types, hb_tag_t TAG> template <typename T, typename Types, hb_tag_t TAG>
struct mortmorx struct mortmorx
{ {
static constexpr hb_tag_t tableTag = TAG; static constexpr hb_tag_t tableTag = TAG;
bool has_data () const { return version != 0; } bool has_data () const { return version != 0; }
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
hb_sanitize_context_t sc;
this->table = sc.reference_table<T> (face);
this->chain_count = table->get_chain_count ();
this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
if (unlikely (!this->accels))
{
this->chain_count = 0;
this->table.destroy ();
this->table = hb_blob_get_empty ();
}
}
~accelerator_t ()
{
for (unsigned int i = 0; i < this->chain_count; i++)
hb_free (this->accels[i]);
hb_free (this->accels);
this->table.destroy ();
}
hb_blob_t *get_blob () const { return table.get_blob (); }
template <typename Chain>
hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
{
if (unlikely (chain_index >= chain_count)) return nullptr;
retry:
auto *accel = accels[chain_index].get_acquire ();
if (unlikely (!accel))
{
accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
if (unlikely (!accel))
return nullptr;
if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
{
hb_free (accel);
goto retry;
}
}
return accel;
}
hb_blob_ptr_t<T> table;
unsigned int chain_count;
hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
};
void compile_flags (const hb_aat_map_builder_t *mapper, void compile_flags (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map) const hb_aat_map_t *map) const
{ {
@ -1167,8 +1335,14 @@ struct mortmorx
} }
} }
unsigned get_chain_count () const
{
return chainCount;
}
void apply (hb_aat_apply_context_t *c, void apply (hb_aat_apply_context_t *c,
const hb_aat_map_t &map) const const hb_aat_map_t &map,
const accelerator_t &accel) const
{ {
if (unlikely (!c->buffer->successful)) return; if (unlikely (!c->buffer->successful)) return;
@ -1179,8 +1353,9 @@ struct mortmorx
unsigned int count = chainCount; unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
c->range_flags = &map.chain_flags[i]; c->range_flags = &map.chain_flags[i];
chain->apply (c); chain->apply (c, chain_accel);
if (unlikely (!c->buffer->successful)) return; if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain<Types>> (*chain); chain = &StructAfter<Chain<Types>> (*chain);
} }
@ -1220,8 +1395,15 @@ struct mortmorx
DEFINE_SIZE_MIN (8); DEFINE_SIZE_MIN (8);
}; };
struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {}; struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {}; struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
struct morx_accelerator_t : morx::accelerator_t {
morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
};
struct mort_accelerator_t : mort::accelerator_t {
mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
};
} /* namespace AAT */ } /* namespace AAT */

View File

@ -211,14 +211,14 @@ void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map) hb_aat_map_t *map)
{ {
const AAT::morx& morx = *mapper->face->table.morx; const AAT::morx& morx = *mapper->face->table.morx->table;
if (morx.has_data ()) if (morx.has_data ())
{ {
morx.compile_flags (mapper, map); morx.compile_flags (mapper, map);
return; return;
} }
const AAT::mort& mort = *mapper->face->table.mort; const AAT::mort& mort = *mapper->face->table.mort->table;
if (mort.has_data ()) if (mort.has_data ())
{ {
mort.compile_flags (mapper, map); mort.compile_flags (mapper, map);
@ -243,8 +243,8 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_bool_t hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face) hb_aat_layout_has_substitution (hb_face_t *face)
{ {
return face->table.morx->has_data () || return face->table.morx->table->has_data () ||
face->table.mort->has_data (); face->table.mort->table->has_data ();
} }
void void
@ -260,26 +260,30 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_aat_map_t map; hb_aat_map_t map;
builder.compile (map); builder.compile (map);
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
if (morx.has_data ())
{ {
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); auto &accel = *font->face->table.morx;
if (!buffer->message (font, "start table morx")) return; const AAT::morx& morx = *accel.table;
morx.apply (&c, map); if (morx.has_data ())
(void) buffer->message (font, "end table morx"); {
return; AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table morx")) return;
morx.apply (&c, map, accel);
(void) buffer->message (font, "end table morx");
return;
}
} }
hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
if (mort.has_data ())
{ {
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); auto &accel = *font->face->table.mort;
if (!buffer->message (font, "start table mort")) return; const AAT::mort& mort = *accel.table;
mort.apply (&c, map); if (mort.has_data ())
(void) buffer->message (font, "end table mort"); {
return; AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table mort")) return;
mort.apply (&c, map, accel);
(void) buffer->message (font, "end table mort");
return;
}
} }
} }
@ -322,7 +326,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
hb_bool_t hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face) hb_aat_layout_has_positioning (hb_face_t *face)
{ {
return face->table.kerx->has_data (); return face->table.kerx->table->has_data ();
} }
void void
@ -330,13 +334,12 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob (); auto &accel = *font->face->table.kerx;
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob); AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table kerx")) return; if (!buffer->message (font, "start table kerx")) return;
c.set_ankr_table (font->face->table.ankr.get ()); c.set_ankr_table (font->face->table.ankr.get ());
kerx.apply (&c); accel.apply (&c);
(void) buffer->message (font, "end table kerx"); (void) buffer->message (font, "end table kerx");
} }

View File

@ -202,8 +202,12 @@ struct BEInt<Type, 4>
/* Floats. */ /* Floats. */
/* We want our rounding towards +infinity. */ /* We want our rounding towards +infinity. */
static inline double
_hb_roundf (double x) { return floor (x + .5); }
static inline float static inline float
_hb_roundf (float x) { return floorf (x + .5f); } _hb_roundf (float x) { return floorf (x + .5f); }
#define roundf(x) _hb_roundf(x) #define roundf(x) _hb_roundf(x)

View File

@ -76,16 +76,12 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
coords = coords_; coords = coords_;
num_coords = num_coords_; num_coords = num_coords_;
varStore = acc.varStore; varStore = acc.varStore;
seen_blend = false;
seen_vsindex_ = false;
scalars.init ();
do_blend = num_coords && coords && varStore->size; do_blend = num_coords && coords && varStore->size;
set_ivs (acc.privateDicts[fd].ivs); set_ivs (acc.privateDicts[fd].ivs);
} }
void fini () void fini ()
{ {
scalars.fini ();
SUPER::fini (); SUPER::fini ();
} }
@ -173,8 +169,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
unsigned int ivs; unsigned int ivs;
hb_vector_t<float> scalars; hb_vector_t<float> scalars;
bool do_blend; bool do_blend;
bool seen_vsindex_; bool seen_vsindex_ = false;
bool seen_blend; bool seen_blend = false;
typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER; typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
}; };

View File

@ -27,9 +27,6 @@
#include "hb.h" #include "hb.h"
HB_BEGIN_DECLS
HB_END_DECLS
#ifdef __cplusplus #ifdef __cplusplus
#include <functional> #include <functional>

View File

@ -100,7 +100,7 @@ HB_OT_CORE_TABLE (OT, MVAR)
/* Legacy kern. */ /* Legacy kern. */
#ifndef HB_NO_OT_KERN #ifndef HB_NO_OT_KERN
HB_OT_CORE_TABLE (OT, kern) HB_OT_ACCELERATOR (OT, kern)
#endif #endif
/* OpenType shaping. */ /* OpenType shaping. */
@ -118,9 +118,9 @@ HB_OT_CORE_TABLE (OT, BASE)
/* AAT shaping. */ /* AAT shaping. */
#ifndef HB_NO_AAT #ifndef HB_NO_AAT
HB_OT_TABLE (AAT, morx) HB_OT_ACCELERATOR (AAT, morx)
HB_OT_TABLE (AAT, mort) HB_OT_ACCELERATOR (AAT, mort)
HB_OT_TABLE (AAT, kerx) HB_OT_ACCELERATOR (AAT, kerx)
HB_OT_TABLE (AAT, ankr) HB_OT_TABLE (AAT, ankr)
HB_OT_TABLE (AAT, trak) HB_OT_TABLE (AAT, trak)
HB_OT_TABLE (AAT, ltag) HB_OT_TABLE (AAT, ltag)

View File

@ -41,6 +41,8 @@
#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gpos-table.hh"
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
void hb_ot_face_t::init0 (hb_face_t *face) void hb_ot_face_t::init0 (hb_face_t *face)

View File

@ -410,7 +410,8 @@ struct hmtxvmtx
font->coords, font->num_coords, font->coords, font->num_coords,
store_cache)); store_cache));
return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
return glyf_advance ? glyf_advance : advance;
#else #else
return advance; return advance;
#endif #endif

View File

@ -86,6 +86,16 @@ struct KernSubTableFormat3
leftClassCount * rightClassCount)); leftClassCount * rightClassCount));
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
set_t set;
if (likely (glyphCount))
set.add_range (0, glyphCount - 1);
left_set.union_ (set);
right_set.union_ (set);
}
protected: protected:
KernSubTableHeader KernSubTableHeader
header; header;
@ -135,16 +145,29 @@ struct KernSubTable
switch (subtable_type) { switch (subtable_type) {
case 0: return_trace (c->dispatch (u.format0)); case 0: return_trace (c->dispatch (u.format0));
#ifndef HB_NO_AAT_SHAPE #ifndef HB_NO_AAT_SHAPE
case 1: return_trace (u.header.apple ? c->dispatch (u.format1, std::forward<Ts> (ds)...) : c->default_return_value ()); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#endif #endif
case 2: return_trace (c->dispatch (u.format2)); case 2: return_trace (c->dispatch (u.format2));
#ifndef HB_NO_AAT_SHAPE #ifndef HB_NO_AAT_SHAPE
case 3: return_trace (u.header.apple ? c->dispatch (u.format3, std::forward<Ts> (ds)...) : c->default_return_value ()); case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
#endif #endif
default: return_trace (c->default_return_value ()); default: return_trace (c->default_return_value ());
} }
} }
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
unsigned int subtable_type = get_type ();
switch (subtable_type) {
case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return;
default: return;
}
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -318,8 +341,9 @@ struct kern
} }
} }
bool apply (AAT::hb_aat_apply_context_t *c) const bool apply (AAT::hb_aat_apply_context_t *c,
{ return dispatch (c); } const AAT::kern_accelerator_data_t *accel_data = nullptr) const
{ return dispatch (c, accel_data); }
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
@ -343,6 +367,41 @@ struct kern
return_trace (dispatch (c)); return_trace (dispatch (c));
} }
AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
{
switch (get_type ()) {
case 0: return u.ot.create_accelerator_data (num_glyphs);
#ifndef HB_NO_AAT_SHAPE
case 1: return u.aat.create_accelerator_data (num_glyphs);
#endif
default:return AAT::kern_accelerator_data_t ();
}
}
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
hb_sanitize_context_t sc;
this->table = sc.reference_table<kern> (face);
this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
}
~accelerator_t ()
{
this->table.destroy ();
}
hb_blob_t *get_blob () const { return table.get_blob (); }
bool apply (AAT::hb_aat_apply_context_t *c) const
{
return table->apply (c, &accel_data);
}
hb_blob_ptr_t<kern> table;
AAT::kern_accelerator_data_t accel_data;
};
protected: protected:
union { union {
HBUINT32 version32; HBUINT32 version32;
@ -356,6 +415,10 @@ struct kern
DEFINE_SIZE_UNION (4, version32); DEFINE_SIZE_UNION (4, version32);
}; };
struct kern_accelerator_t : kern::accelerator_t {
kern_accelerator_t (hb_face_t *face) : kern::accelerator_t (face) {}
};
} /* namespace OT */ } /* namespace OT */

View File

@ -125,6 +125,20 @@ struct BaseCoordFormat3
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (!c->plan->pinned_at_default)
{
unsigned var_idx = (this+deviceTable).get_variation_index ();
if (var_idx != VarIdx::NO_VARIATION)
{
hb_pair_t<unsigned, int> *v;
if (!c->plan->base_variation_idx_map.has (var_idx, &v))
return_trace (false);
if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v),
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
return_trace (false);
}
}
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
this, 0, this, 0,
hb_serialize_context_t::Head, hb_serialize_context_t::Head,
@ -401,11 +415,12 @@ struct BaseLangSysRecord
bool has_data () const { return baseLangSysTag; } bool has_data () const { return baseLangSysTag; }
const MinMax &get_min_max () const { return this+minMax; } const MinMax &get_min_max (const void* base) const { return base+minMax; }
void collect_variation_indices (const hb_subset_plan_t* plan, void collect_variation_indices (const void* base,
const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const hb_set_t& varidx_set /* OUT */) const
{ (this+minMax).collect_variation_indices (plan, varidx_set); } { (base+minMax).collect_variation_indices (plan, varidx_set); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const void *base) const const void *base) const
@ -438,7 +453,7 @@ struct BaseScript
const MinMax &get_min_max (hb_tag_t language_tag) const const MinMax &get_min_max (hb_tag_t language_tag) const
{ {
const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag); const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
return record.has_data () ? record.get_min_max () : this+defaultMinMax; return record.has_data () ? record.get_min_max (this) : this+defaultMinMax;
} }
const BaseCoord &get_base_coord (int baseline_tag_index) const const BaseCoord &get_base_coord (int baseline_tag_index) const
@ -454,7 +469,7 @@ struct BaseScript
(this+defaultMinMax).collect_variation_indices (plan, varidx_set); (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
for (const BaseLangSysRecord& _ : baseLangSysRecords) for (const BaseLangSysRecord& _ : baseLangSysRecords)
_.collect_variation_indices (plan, varidx_set); _.collect_variation_indices (this, plan, varidx_set);
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
@ -705,6 +720,46 @@ struct BASE
(this+vAxis).collect_variation_indices (plan, varidx_set); (this+vAxis).collect_variation_indices (plan, varidx_set);
} }
bool subset_varstore (hb_subset_context_t *c,
BASE *out /* OUT */) const
{
TRACE_SUBSET (this);
if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
return_trace (false);
if (!c->plan->normalized_coords)
return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
if (c->plan->all_axes_pinned)
return_trace (true);
item_variations_t item_vars;
if (!item_vars.instantiate (this+varStore, c->plan, true, true,
c->plan->base_varstore_inner_maps.as_array ()))
return_trace (false);
if (!out->varStore.serialize_serialize (c->serializer,
item_vars.has_long_word (),
c->plan->axis_tags,
item_vars.get_region_list (),
item_vars.get_vardata_encodings ()))
return_trace (false);
const hb_map_t &varidx_map = item_vars.get_varidx_map ();
/* base_variation_idx_map in the plan is old_varidx->(varidx, delta)
* mapping, new varidx is generated for subsetting, we need to remap this
* after instancing */
for (auto _ : c->plan->base_variation_idx_map.iter_ref ())
{
uint32_t varidx = _.second.first;
uint32_t *new_varidx;
if (varidx_map.has (varidx, &new_varidx))
_.second.first = *new_varidx;
else
_.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
}
return_trace (true);
}
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -712,19 +767,15 @@ struct BASE
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
out->version = version; out->version = version;
if (has_var_store () && !subset_varstore (c, out))
return_trace (false);
if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this)) if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
return_trace (false); return_trace (false);
if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this)) if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
return_trace (false); return_trace (false);
if (has_var_store ())
{
if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
return_trace (false);
return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
}
return_trace (true); return_trace (true);
} }

View File

@ -2641,7 +2641,7 @@ struct VarRegionList
float max_val = axis_region->endCoord.to_float (); float max_val = axis_region->endCoord.to_float ();
if (def_val != 0.f) if (def_val != 0.f)
axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val)); axis_tuples.set (*axis_tag, Triple ((double) min_val, (double) def_val, (double) max_val));
axis_region++; axis_region++;
} }
return !axis_tuples.in_error (); return !axis_tuples.in_error ();
@ -3208,6 +3208,8 @@ struct ItemVariationStore
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ {
hb_inc_bimap_t *map = inner_maps.push (); hb_inc_bimap_t *map = inner_maps.push ();
if (!c->propagate_error(inner_maps))
return_trace(nullptr);
auto &data = this+dataSets[i]; auto &data = this+dataSets[i];
unsigned itemCount = data.get_item_count (); unsigned itemCount = data.get_item_count ();
@ -3326,19 +3328,19 @@ struct ConditionFormat1
return_trace (false); return_trace (false);
const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location; const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
Triple axis_limit{-1.f, 0.f, 1.f}; Triple axis_limit{-1.0, 0.0, 1.0};
Triple *normalized_limit; Triple *normalized_limit;
if (normalized_axes_location.has (*axis_tag, &normalized_limit)) if (normalized_axes_location.has (*axis_tag, &normalized_limit))
axis_limit = *normalized_limit; axis_limit = *normalized_limit;
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances; const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
TripleDistances axis_triple_distances{1.f, 1.f}; TripleDistances axis_triple_distances{1.0, 1.0};
TripleDistances *triple_dists; TripleDistances *triple_dists;
if (axes_triple_distances.has (*axis_tag, &triple_dists)) if (axes_triple_distances.has (*axis_tag, &triple_dists))
axis_triple_distances = *triple_dists; axis_triple_distances = *triple_dists;
float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false); float normalized_min = renormalizeValue ((double) filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false); float normalized_max = renormalizeValue ((double) filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
out->filterRangeMinValue.set_float (normalized_min); out->filterRangeMinValue.set_float (normalized_min);
out->filterRangeMaxValue.set_float (normalized_max); out->filterRangeMaxValue.set_float (normalized_max);
@ -3356,7 +3358,7 @@ struct ConditionFormat1
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex); hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
Triple axis_range (-1.f, 0.f, 1.f); Triple axis_range (-1.0, 0.0, 1.0);
Triple *axis_limit; Triple *axis_limit;
bool axis_set_by_user = false; bool axis_set_by_user = false;
if (c->axes_location->has (axis_tag, &axis_limit)) if (c->axes_location->has (axis_tag, &axis_limit))

View File

@ -1254,7 +1254,7 @@ static bool match_input (hb_ot_apply_context_t *c,
match_func_t match_func, match_func_t match_func,
const void *match_data, const void *match_data,
unsigned int *end_position, unsigned int *end_position,
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], unsigned int *match_positions,
unsigned int *p_total_component_count = nullptr) unsigned int *p_total_component_count = nullptr)
{ {
TRACE_APPLY (nullptr); TRACE_APPLY (nullptr);
@ -1378,7 +1378,7 @@ static bool match_input (hb_ot_apply_context_t *c,
} }
static inline bool ligate_input (hb_ot_apply_context_t *c, static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */ unsigned int count, /* Including the first glyph */
const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ const unsigned int *match_positions, /* Including the first glyph */
unsigned int match_end, unsigned int match_end,
hb_codepoint_t lig_glyph, hb_codepoint_t lig_glyph,
unsigned int total_component_count) unsigned int total_component_count)
@ -1686,7 +1686,7 @@ static inline void recurse_lookups (context_t *c,
static inline void apply_lookup (hb_ot_apply_context_t *c, static inline void apply_lookup (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */ unsigned int count, /* Including the first glyph */
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int *match_positions, /* Including the first glyph */
unsigned int lookupCount, unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_end) unsigned int match_end)
@ -1694,6 +1694,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer; hb_buffer_t *buffer = c->buffer;
int end; int end;
unsigned int *match_positions_input = match_positions;
unsigned int match_positions_count = count;
/* All positions are distance from beginning of *output* buffer. /* All positions are distance from beginning of *output* buffer.
* Adjust. */ * Adjust. */
{ {
@ -1797,6 +1800,27 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
{ {
if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH)) if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
break; break;
if (unlikely (delta + count > match_positions_count))
{
unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5);
if (match_positions == match_positions_input)
{
match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0]));
if (unlikely (!match_positions))
break;
memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0]));
match_positions_count = new_match_positions_count;
}
else
{
unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0]));
if (unlikely (!new_match_positions))
break;
match_positions = new_match_positions;
match_positions_count = new_match_positions_count;
}
}
} }
else else
{ {
@ -1820,6 +1844,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
match_positions[next] += delta; match_positions[next] += delta;
} }
if (match_positions != match_positions_input)
hb_free (match_positions);
(void) buffer->move_to (end); (void) buffer->move_to (end);
} }
@ -1920,8 +1947,18 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
const ContextApplyLookupContext &lookup_context) const ContextApplyLookupContext &lookup_context)
{ {
if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
if (unlikely (!match_positions))
return false;
}
unsigned match_end = 0; unsigned match_end = 0;
unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; bool ret = false;
if (match_input (c, if (match_input (c,
inputCount, input, inputCount, input,
lookup_context.funcs.match, lookup_context.match_data, lookup_context.funcs.match, lookup_context.match_data,
@ -1932,13 +1969,18 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
inputCount, match_positions, inputCount, match_positions,
lookupCount, lookupRecord, lookupCount, lookupRecord,
match_end); match_end);
return true; ret = true;
} }
else else
{ {
c->buffer->unsafe_to_concat (c->buffer->idx, match_end); c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
return false; ret = false;
} }
if (unlikely (match_positions != match_positions_stack))
hb_free (match_positions);
return ret;
} }
template <typename Types> template <typename Types>
@ -3018,9 +3060,20 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
const ChainContextApplyLookupContext &lookup_context) const ChainContextApplyLookupContext &lookup_context)
{ {
if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
if (unlikely (!match_positions))
return false;
}
unsigned start_index = c->buffer->out_len;
unsigned end_index = c->buffer->idx; unsigned end_index = c->buffer->idx;
unsigned match_end = 0; unsigned match_end = 0;
unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; bool ret = true;
if (!(match_input (c, if (!(match_input (c,
inputCount, input, inputCount, input,
lookup_context.funcs.match[1], lookup_context.match_data[1], lookup_context.funcs.match[1], lookup_context.match_data[1],
@ -3031,17 +3084,18 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
match_end, &end_index))) match_end, &end_index)))
{ {
c->buffer->unsafe_to_concat (c->buffer->idx, end_index); c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
return false; ret = false;
goto done;
} }
unsigned start_index = c->buffer->out_len;
if (!match_backtrack (c, if (!match_backtrack (c,
backtrackCount, backtrack, backtrackCount, backtrack,
lookup_context.funcs.match[0], lookup_context.match_data[0], lookup_context.funcs.match[0], lookup_context.match_data[0],
&start_index)) &start_index))
{ {
c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
return false; ret = false;
goto done;
} }
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
@ -3049,7 +3103,12 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
inputCount, match_positions, inputCount, match_positions,
lookupCount, lookupRecord, lookupCount, lookupRecord,
match_end); match_end);
return true; done:
if (unlikely (match_positions != match_positions_stack))
hb_free (match_positions);
return ret;
} }
template <typename Types> template <typename Types>
@ -4328,7 +4387,7 @@ struct hb_ot_layout_lookup_accelerator_t
thiz->digest.init (); thiz->digest.init ();
for (auto& subtable : hb_iter (thiz->subtables, count)) for (auto& subtable : hb_iter (thiz->subtables, count))
thiz->digest.add (subtable.digest); thiz->digest.union_ (subtable.digest);
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx; thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;

View File

@ -87,7 +87,7 @@ using OT::Layout::GPOS;
bool bool
hb_ot_layout_has_kerning (hb_face_t *face) hb_ot_layout_has_kerning (hb_face_t *face)
{ {
return face->table.kern->has_data (); return face->table.kern->table->has_data ();
} }
/** /**
@ -103,7 +103,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
bool bool
hb_ot_layout_has_machine_kerning (hb_face_t *face) hb_ot_layout_has_machine_kerning (hb_face_t *face)
{ {
return face->table.kern->has_state_machine (); return face->table.kern->table->has_state_machine ();
} }
/** /**
@ -123,7 +123,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
bool bool
hb_ot_layout_has_cross_kerning (hb_face_t *face) hb_ot_layout_has_cross_kerning (hb_face_t *face)
{ {
return face->table.kern->has_cross_stream (); return face->table.kern->table->has_cross_stream ();
} }
void void
@ -132,7 +132,7 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
hb_blob_t *blob = font->face->table.kern.get_blob (); hb_blob_t *blob = font->face->table.kern.get_blob ();
const AAT::kern& kern = *blob->as<AAT::kern> (); const auto& kern = *font->face->table.kern;
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob); AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);

View File

@ -272,7 +272,7 @@ struct OS2
Triple *axis_range; Triple *axis_range;
if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range)) if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
{ {
unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f))); unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0, 1000.0)));
if (os2_prime->usWeightClass != weight_class) if (os2_prime->usWeightClass != weight_class)
os2_prime->usWeightClass = weight_class; os2_prime->usWeightClass = weight_class;
} }

View File

@ -116,7 +116,7 @@ struct post
Triple *axis_range; Triple *axis_range;
if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range)) if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
{ {
float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f)); float italic_angle = hb_max (-90.0, hb_min (axis_range->middle, 90.0));
if (post_prime->italicAngle.to_float () != italic_angle) if (post_prime->italicAngle.to_float () != italic_angle)
post_prime->italicAngle.set_float (italic_angle); post_prime->italicAngle.set_float (italic_angle);
} }

View File

@ -63,8 +63,9 @@ static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_valu
if (!user_axes_location->has (axis_tag)) if (!user_axes_location->has (axis_tag))
return false; return false;
double axis_value_double = static_cast<double>(axis_value);
Triple axis_range = user_axes_location->get (axis_tag); Triple axis_range = user_axes_location->get (axis_tag);
return (axis_value < axis_range.minimum || axis_value > axis_range.maximum); return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum);
} }
struct StatAxisRecord struct StatAxisRecord

View File

@ -2818,9 +2818,10 @@ out:
* @tag: A language tag. * @tag: A language tag.
* *
* Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
* many language tags) and the best tag is not the alphabetically first, or if * many language tags) and the best tag is not the first (sorted alphabetically,
* the best tag consists of multiple subtags, or if the best tag does not appear * with two-letter tags having priority over all three-letter tags), or if the
* in #ot_languages. * best tag consists of multiple subtags, or if the best tag does not appear in
* #ot_languages2 or #ot_languages3.
* *
* Return value: The #hb_language_t corresponding to the BCP 47 language tag, * Return value: The #hb_language_t corresponding to the BCP 47 language tag,
* or #HB_LANGUAGE_INVALID if @tag is not ambiguous. * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
@ -2834,8 +2835,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("alt", -1); /* Southern Altai */ return hb_language_from_string ("alt", -1); /* Southern Altai */
case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */ return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */
case HB_TAG('A','R','A',' '): /* Arabic */
return hb_language_from_string ("ar", -1); /* Arabic [macrolanguage] */
case HB_TAG('A','R','K',' '): /* Rakhine */ case HB_TAG('A','R','K',' '): /* Rakhine */
return hb_language_from_string ("rki", -1); /* Rakhine */ return hb_language_from_string ("rki", -1); /* Rakhine */
case HB_TAG('A','T','H',' '): /* Athapaskan */ case HB_TAG('A','T','H',' '): /* Athapaskan */
@ -2856,12 +2855,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("din", -1); /* Dinka [macrolanguage] */ return hb_language_from_string ("din", -1); /* Dinka [macrolanguage] */
case HB_TAG('D','R','I',' '): /* Dari */ case HB_TAG('D','R','I',' '): /* Dari */
return hb_language_from_string ("prs", -1); /* Dari */ return hb_language_from_string ("prs", -1); /* Dari */
case HB_TAG('D','Z','N',' '): /* Dzongkha */
return hb_language_from_string ("dz", -1); /* Dzongkha */
case HB_TAG('E','T','I',' '): /* Estonian */
return hb_language_from_string ("et", -1); /* Estonian [macrolanguage] */
case HB_TAG('F','A','R',' '): /* Persian */
return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */
case HB_TAG('G','O','N',' '): /* Gondi */ case HB_TAG('G','O','N',' '): /* Gondi */
return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */ return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */
case HB_TAG('H','M','A',' '): /* High Mari */ case HB_TAG('H','M','A',' '): /* High Mari */
@ -2876,10 +2869,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("iba", -1); /* Iban */ return hb_language_from_string ("iba", -1); /* Iban */
case HB_TAG('I','J','O',' '): /* Ijo */ case HB_TAG('I','J','O',' '): /* Ijo */
return hb_language_from_string ("ijo", -1); /* Ijo [collection] */ return hb_language_from_string ("ijo", -1); /* Ijo [collection] */
case HB_TAG('I','N','U',' '): /* Inuktitut */
return hb_language_from_string ("iu", -1); /* Inuktitut [macrolanguage] */
case HB_TAG('I','P','K',' '): /* Inupiat */
return hb_language_from_string ("ik", -1); /* Inupiaq [macrolanguage] */
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */ return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */
case HB_TAG('I','R','T',' '): /* Irish Traditional */ case HB_TAG('I','R','T',' '): /* Irish Traditional */
@ -2890,36 +2879,24 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("kln", -1); /* Kalenjin [macrolanguage] */ return hb_language_from_string ("kln", -1); /* Kalenjin [macrolanguage] */
case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */ case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */
return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
case HB_TAG('K','N','R',' '): /* Kanuri */
return hb_language_from_string ("kr", -1); /* Kanuri [macrolanguage] */
case HB_TAG('K','O','H',' '): /* Korean Old Hangul */ case HB_TAG('K','O','H',' '): /* Korean Old Hangul */
return hb_language_from_string ("okm", -1); /* Middle Korean (10th-16th cent.) */ return hb_language_from_string ("okm", -1); /* Middle Korean (10th-16th cent.) */
case HB_TAG('K','O','K',' '): /* Konkani */ case HB_TAG('K','O','K',' '): /* Konkani */
return hb_language_from_string ("kok", -1); /* Konkani [macrolanguage] */ return hb_language_from_string ("kok", -1); /* Konkani [macrolanguage] */
case HB_TAG('K','O','M',' '): /* Komi */
return hb_language_from_string ("kv", -1); /* Komi [macrolanguage] */
case HB_TAG('K','P','L',' '): /* Kpelle */ case HB_TAG('K','P','L',' '): /* Kpelle */
return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */ return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */
case HB_TAG('K','R','N',' '): /* Karen */ case HB_TAG('K','R','N',' '): /* Karen */
return hb_language_from_string ("kar", -1); /* Karen [collection] */ return hb_language_from_string ("kar", -1); /* Karen [collection] */
case HB_TAG('K','U','I',' '): /* Kui */ case HB_TAG('K','U','I',' '): /* Kui */
return hb_language_from_string ("uki", -1); /* Kui (India) */ return hb_language_from_string ("uki", -1); /* Kui (India) */
case HB_TAG('K','U','R',' '): /* Kurdish */
return hb_language_from_string ("ku", -1); /* Kurdish [macrolanguage] */
case HB_TAG('L','M','A',' '): /* Low Mari */ case HB_TAG('L','M','A',' '): /* Low Mari */
return hb_language_from_string ("mhr", -1); /* Eastern Mari */ return hb_language_from_string ("mhr", -1); /* Eastern Mari */
case HB_TAG('L','U','H',' '): /* Luyia */ case HB_TAG('L','U','H',' '): /* Luyia */
return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */ return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */
case HB_TAG('L','V','I',' '): /* Latvian */
return hb_language_from_string ("lv", -1); /* Latvian [macrolanguage] */
case HB_TAG('M','A','W',' '): /* Marwari */ case HB_TAG('M','A','W',' '): /* Marwari */
return hb_language_from_string ("mwr", -1); /* Marwari [macrolanguage] */ return hb_language_from_string ("mwr", -1); /* Marwari [macrolanguage] */
case HB_TAG('M','L','G',' '): /* Malagasy */
return hb_language_from_string ("mg", -1); /* Malagasy [macrolanguage] */
case HB_TAG('M','L','Y',' '): /* Malay */ case HB_TAG('M','L','Y',' '): /* Malay */
return hb_language_from_string ("ms", -1); /* Malay [macrolanguage] */ return hb_language_from_string ("ms", -1); /* Malay [macrolanguage] */
case HB_TAG('M','N','G',' '): /* Mongolian */
return hb_language_from_string ("mn", -1); /* Mongolian [macrolanguage] */
case HB_TAG('M','N','K',' '): /* Maninka */ case HB_TAG('M','N','K',' '): /* Maninka */
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */ return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */ case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */
@ -2930,26 +2907,16 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("myn", -1); /* Mayan [collection] */ return hb_language_from_string ("myn", -1); /* Mayan [collection] */
case HB_TAG('N','A','H',' '): /* Nahuatl */ case HB_TAG('N','A','H',' '): /* Nahuatl */
return hb_language_from_string ("nah", -1); /* Nahuatl [collection] */ return hb_language_from_string ("nah", -1); /* Nahuatl [collection] */
case HB_TAG('N','E','P',' '): /* Nepali */
return hb_language_from_string ("ne", -1); /* Nepali [macrolanguage] */
case HB_TAG('N','I','S',' '): /* Nisi */ case HB_TAG('N','I','S',' '): /* Nisi */
return hb_language_from_string ("njz", -1); /* Nyishi */ return hb_language_from_string ("njz", -1); /* Nyishi */
case HB_TAG('N','O','R',' '): /* Norwegian */ case HB_TAG('N','O','R',' '): /* Norwegian */
return hb_language_from_string ("no", -1); /* Norwegian [macrolanguage] */ return hb_language_from_string ("no", -1); /* Norwegian [macrolanguage] */
case HB_TAG('O','J','B',' '): /* Ojibway */
return hb_language_from_string ("oj", -1); /* Ojibwa [macrolanguage] */
case HB_TAG('O','R','O',' '): /* Oromo */
return hb_language_from_string ("om", -1); /* Oromo [macrolanguage] */
case HB_TAG('P','A','S',' '): /* Pashto */
return hb_language_from_string ("ps", -1); /* Pashto [macrolanguage] */
case HB_TAG('P','G','R',' '): /* Polytonic Greek */ case HB_TAG('P','G','R',' '): /* Polytonic Greek */
return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */ return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */
case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */ case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */
return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */ return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */
case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */ case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */
return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */ return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */
case HB_TAG('Q','U','Z',' '): /* Quechua */
return hb_language_from_string ("qu", -1); /* Quechua [macrolanguage] */
case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */ case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */
return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */ return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */
case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */ case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */
@ -2960,10 +2927,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ro", -1); /* Romanian */ return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */ case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */ return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
case HB_TAG('S','A','N',' '): /* Sanskrit */
return hb_language_from_string ("sa", -1); /* Sanskrit [macrolanguage] */
case HB_TAG('S','Q','I',' '): /* Albanian */
return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */ case HB_TAG('S','R','B',' '): /* Serbian */
return hb_language_from_string ("sr", -1); /* Serbian */ return hb_language_from_string ("sr", -1); /* Serbian */
case HB_TAG('S','X','T',' '): /* Sutu */ case HB_TAG('S','X','T',' '): /* Sutu */

View File

@ -80,7 +80,7 @@ struct AxisValueMap
bool is_outside_axis_range (const Triple& axis_range) const bool is_outside_axis_range (const Triple& axis_range) const
{ {
float from_coord = coords[0].to_float (); double from_coord = (double) coords[0].to_float ();
return !axis_range.contains (from_coord); return !axis_range.contains (from_coord);
} }
@ -100,8 +100,8 @@ struct AxisValueMap
float from_coord = coords[0].to_float (); float from_coord = coords[0].to_float ();
float to_coord = coords[1].to_float (); float to_coord = coords[1].to_float ();
from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances); from_coord = renormalizeValue ((double) from_coord, unmapped_range, triple_distances);
to_coord = renormalizeValue (to_coord, axis_range, triple_distances); to_coord = renormalizeValue ((double) to_coord, axis_range, triple_distances);
coords[0].set_float (from_coord); coords[0].set_float (from_coord);
coords[1].set_float (to_coord); coords[1].set_float (to_coord);
@ -197,7 +197,7 @@ struct SegmentMaps : Array16Of<AxisValueMap>
unmapped_val.set_int (unmap (val.to_int ())); unmapped_val.set_int (unmap (val.to_int ()));
float unmapped_max = unmapped_val.to_float (); float unmapped_max = unmapped_val.to_float ();
return Triple{unmapped_min, unmapped_middle, unmapped_max}; return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max};
} }
bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const

View File

@ -299,13 +299,13 @@ struct TupleVariationHeader
start = hb_min (peak, 0.f); start = hb_min (peak, 0.f);
end = hb_max (peak, 0.f); end = hb_max (peak, 0.f);
} }
axis_tuples.set (*axis_tag, Triple (start, peak, end)); axis_tuples.set (*axis_tag, Triple ((double) start, (double) peak, (double) end));
} }
return true; return true;
} }
float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count, double 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> shared_tuples,
const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
{ {
@ -321,13 +321,13 @@ struct TupleVariationHeader
{ {
unsigned int index = get_index (); unsigned int index = get_index ();
if (unlikely ((index + 1) * coord_count > shared_tuples.length)) if (unlikely ((index + 1) * coord_count > shared_tuples.length))
return 0.f; return 0.0;
peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ; peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
if (shared_tuple_active_idx) if (shared_tuple_active_idx)
{ {
if (unlikely (index >= shared_tuple_active_idx->length)) if (unlikely (index >= shared_tuple_active_idx->length))
return 0.f; return 0.0;
auto _ = (*shared_tuple_active_idx).arrayZ[index]; auto _ = (*shared_tuple_active_idx).arrayZ[index];
if (_.second != -1) if (_.second != -1)
{ {
@ -352,7 +352,7 @@ struct TupleVariationHeader
end_tuple = get_end_tuple (coord_count).arrayZ; end_tuple = get_end_tuple (coord_count).arrayZ;
} }
float scalar = 1.f; double scalar = 1.0;
for (unsigned int i = start_idx; i < end_idx; i += step) for (unsigned int i = start_idx; i < end_idx; i += step)
{ {
int peak = peak_tuple[i].to_int (); int peak = peak_tuple[i].to_int ();
@ -367,15 +367,15 @@ struct TupleVariationHeader
int end = end_tuple[i].to_int (); int end = end_tuple[i].to_int ();
if (unlikely (start > peak || peak > end || if (unlikely (start > peak || peak > end ||
(start < 0 && end > 0 && peak))) continue; (start < 0 && end > 0 && peak))) continue;
if (v < start || v > end) return 0.f; if (v < start || v > end) return 0.0;
if (v < peak) if (v < peak)
{ if (peak != start) scalar *= (float) (v - start) / (peak - start); } { if (peak != start) scalar *= (double) (v - start) / (peak - start); }
else else
{ if (peak != end) scalar *= (float) (end - v) / (end - peak); } { if (peak != end) scalar *= (double) (end - v) / (end - peak); }
} }
else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f; else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.0;
else else
scalar *= (float) v / peak; scalar *= (double) v / peak;
} }
return scalar; return scalar;
} }
@ -444,10 +444,10 @@ struct tuple_delta_t
/* indices_length = point_count, indice[i] = 1 means point i is referenced */ /* indices_length = point_count, indice[i] = 1 means point i is referenced */
hb_vector_t<bool> indices; hb_vector_t<bool> indices;
hb_vector_t<float> deltas_x; hb_vector_t<double> deltas_x;
/* empty for cvar tuples */ /* empty for cvar tuples */
hb_vector_t<float> deltas_y; hb_vector_t<double> deltas_y;
/* compiled data: header and deltas /* compiled data: header and deltas
* compiled point data is saved in a hashmap within tuple_variations_t cause * compiled point data is saved in a hashmap within tuple_variations_t cause
@ -513,9 +513,9 @@ struct tuple_delta_t
return *this; return *this;
} }
tuple_delta_t& operator *= (float scalar) tuple_delta_t& operator *= (double scalar)
{ {
if (scalar == 1.0f) if (scalar == 1.0)
return *this; return *this;
unsigned num = indices.length; unsigned num = indices.length;
@ -546,18 +546,18 @@ struct tuple_delta_t
return out; return out;
} }
if ((tent->minimum < 0.f && tent->maximum > 0.f) || if ((tent->minimum < 0.0 && tent->maximum > 0.0) ||
!(tent->minimum <= tent->middle && tent->middle <= tent->maximum)) !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
return out; return out;
if (tent->middle == 0.f) if (tent->middle == 0.0)
{ {
out.push (*this); out.push (*this);
return out; return out;
} }
result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances); rebase_tent_result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
for (auto t : solutions) for (auto &t : solutions)
{ {
tuple_delta_t new_var = *this; tuple_delta_t new_var = *this;
if (t.second == Triple ()) if (t.second == Triple ())
@ -729,8 +729,8 @@ struct tuple_delta_t
{ return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); } { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
bool compile_deltas (const hb_vector_t<bool> &point_indices, bool compile_deltas (const hb_vector_t<bool> &point_indices,
const hb_vector_t<float> &x_deltas, const hb_vector_t<double> &x_deltas,
const hb_vector_t<float> &y_deltas, const hb_vector_t<double> &y_deltas,
hb_vector_t<char> &compiled_deltas /* OUT */) hb_vector_t<char> &compiled_deltas /* OUT */)
{ {
hb_vector_t<int> rounded_deltas; hb_vector_t<int> rounded_deltas;
@ -1000,9 +1000,13 @@ struct tuple_delta_t
{ {
i = next_index (i, start_point, end_point); i = next_index (i, start_point, end_point);
if (i == next) break; if (i == next) break;
deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x, deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x,
(double) orig_points.arrayZ[prev].x,
(double) orig_points.arrayZ[next].x,
deltas_x.arrayZ[prev], deltas_x.arrayZ[next]); deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y, deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y,
(double) orig_points.arrayZ[prev].y,
(double) orig_points.arrayZ[next].y,
deltas_y.arrayZ[prev], deltas_y.arrayZ[next]); deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
inferred_idxes.add (i); inferred_idxes.add (i);
if (--unref_count == 0) goto no_more_gaps; if (--unref_count == 0) goto no_more_gaps;
@ -1020,8 +1024,8 @@ struct tuple_delta_t
{ {
if (!inferred_idxes.has (i)) if (!inferred_idxes.has (i))
{ {
deltas_x.arrayZ[i] = 0.f; deltas_x.arrayZ[i] = 0.0;
deltas_y.arrayZ[i] = 0.f; deltas_y.arrayZ[i] = 0.0;
} }
indices[i] = true; indices[i] = true;
} }
@ -1031,7 +1035,7 @@ struct tuple_delta_t
bool optimize (const contour_point_vector_t& contour_points, bool optimize (const contour_point_vector_t& contour_points,
bool is_composite, bool is_composite,
float tolerance = 0.5f) double tolerance = 0.5 + 1e-10)
{ {
unsigned count = contour_points.length; unsigned count = contour_points.length;
if (deltas_x.length != count || if (deltas_x.length != count ||
@ -1062,7 +1066,7 @@ struct tuple_delta_t
if (ref_count == count) return true; if (ref_count == count) return true;
hb_vector_t<float> opt_deltas_x, opt_deltas_y; hb_vector_t<double> opt_deltas_x, opt_deltas_y;
bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0); bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
if (is_comp_glyph_wo_deltas) if (is_comp_glyph_wo_deltas)
{ {
@ -1194,16 +1198,16 @@ struct tuple_delta_t
return compiled_points.resize (pos, false); return compiled_points.resize (pos, false);
} }
static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta) static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta)
{ {
if (prev_val == next_val) if (prev_val == next_val)
return (prev_delta == next_delta) ? prev_delta : 0.f; return (prev_delta == next_delta) ? prev_delta : 0.0;
else if (target_val <= hb_min (prev_val, next_val)) 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)) 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;
float r = (target_val - prev_val) / (next_val - prev_val); double r = (target_val - prev_val) / (next_val - prev_val);
return prev_delta + r * (next_delta - prev_delta); return prev_delta + r * (next_delta - prev_delta);
} }
@ -1347,9 +1351,9 @@ struct TupleVariationData
unsigned idx = apply_to_all ? i : indices[i]; unsigned idx = apply_to_all ? i : indices[i];
if (idx >= point_count) continue; if (idx >= point_count) continue;
var.indices[idx] = true; var.indices[idx] = true;
var.deltas_x[idx] = static_cast<float> (deltas_x[i]); var.deltas_x[idx] = deltas_x[i];
if (is_gvar) if (is_gvar)
var.deltas_y[idx] = static_cast<float> (deltas_y[i]); var.deltas_y[idx] = deltas_y[i];
} }
tuple_vars.push (std::move (var)); tuple_vars.push (std::move (var));
} while (iterator.move_to_next ()); } while (iterator.move_to_next ());
@ -1367,15 +1371,15 @@ struct TupleVariationData
/* NULL offset, to keep original varidx valid, just return */ /* NULL offset, to keep original varidx valid, just return */
if (&var_data == &Null (VarData)) if (&var_data == &Null (VarData))
return true; return true;
unsigned num_regions = var_data.get_region_index_count (); unsigned num_regions = var_data.get_region_index_count ();
if (!tuple_vars.alloc (num_regions)) return false; if (!tuple_vars.alloc (num_regions)) return false;
item_count = inner_map ? inner_map->get_population () : var_data.get_item_count (); item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
if (!item_count) return true; if (!item_count) return true;
unsigned row_size = var_data.get_row_size (); unsigned row_size = var_data.get_row_size ();
const HBUINT8 *delta_bytes = var_data.get_delta_bytes (); const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
for (unsigned r = 0; r < num_regions; r++) for (unsigned r = 0; r < num_regions; r++)
{ {
/* In VarData, deltas are organized in rows, convert them into /* In VarData, deltas are organized in rows, convert them into
@ -1384,14 +1388,14 @@ struct TupleVariationData
if (!tuple.deltas_x.resize (item_count, false) || if (!tuple.deltas_x.resize (item_count, false) ||
!tuple.indices.resize (item_count, false)) !tuple.indices.resize (item_count, false))
return false; return false;
for (unsigned i = 0; i < item_count; i++) for (unsigned i = 0; i < item_count; i++)
{ {
tuple.indices.arrayZ[i] = true; tuple.indices.arrayZ[i] = true;
tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i, tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
r, delta_bytes, row_size); r, delta_bytes, row_size);
} }
unsigned region_index = var_data.get_region_index (r); unsigned region_index = var_data.get_region_index (r);
if (region_index >= regions.length) return false; if (region_index >= regions.length) return false;
tuple.axis_tuples = regions.arrayZ[region_index]; tuple.axis_tuples = regions.arrayZ[region_index];
@ -1425,7 +1429,7 @@ struct TupleVariationData
Triple *axis_limit; Triple *axis_limit;
if (!normalized_axes_location.has (axis_tag, &axis_limit)) if (!normalized_axes_location.has (axis_tag, &axis_limit))
return false; return false;
TripleDistances axis_triple_distances{1.f, 1.f}; TripleDistances axis_triple_distances{1.0, 1.0};
if (axes_triple_distances.has (axis_tag)) if (axes_triple_distances.has (axis_tag))
axis_triple_distances = axes_triple_distances.get (axis_tag); axis_triple_distances = axes_triple_distances.get (axis_tag);
@ -1503,11 +1507,11 @@ struct TupleVariationData
return false; return false;
continue; continue;
} }
hb_vector_t<char> compiled_point_data; hb_vector_t<char> compiled_point_data;
if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data)) if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
return false; return false;
if (!point_data_map.set (points_set, std::move (compiled_point_data)) || if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
!point_set_count_map.set (points_set, 1)) !point_set_count_map.set (points_set, 1))
return false; return false;
@ -1547,7 +1551,7 @@ struct TupleVariationData
for (tuple_delta_t& var : tuple_vars) for (tuple_delta_t& var : tuple_vars)
if (!var.calc_inferred_deltas (contour_points)) if (!var.calc_inferred_deltas (contour_points))
return false; return false;
return true; return true;
} }
@ -1874,7 +1878,7 @@ struct TupleVariationData
if (!tuple_variations.serialize_var_headers (c, total_header_len)) if (!tuple_variations.serialize_var_headers (c, total_header_len))
return_trace (false); return_trace (false);
unsigned data_offset = min_size + total_header_len; unsigned data_offset = min_size + total_header_len;
if (!is_gvar) data_offset += 4; if (!is_gvar) data_offset += 4;
if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@ -2335,12 +2339,12 @@ struct item_variations_t
/* just sanity check, this shouldn't happen */ /* just sanity check, this shouldn't happen */
if (encoding.is_empty ()) if (encoding.is_empty ())
return false; return false;
unsigned num_rows = encoding.items.length; unsigned num_rows = encoding.items.length;
/* sort rows, make result deterministic */ /* sort rows, make result deterministic */
encoding.items.qsort (_cmp_row); encoding.items.qsort (_cmp_row);
/* compile old to new var_idxes mapping */ /* compile old to new var_idxes mapping */
for (unsigned minor = 0; minor < num_rows; minor++) for (unsigned minor = 0; minor < num_rows; minor++)
{ {

View File

@ -43,7 +43,7 @@ static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DO
unsigned axis_index, unsigned axis_index,
Triple axis_limit) Triple axis_limit)
{ {
float axis_coord = coords[axis_index].to_float (); double axis_coord = static_cast<double>(coords[axis_index].to_float ());
if (axis_limit.is_point ()) if (axis_limit.is_point ())
{ {
if (axis_limit.minimum != axis_coord) if (axis_limit.minimum != axis_coord)
@ -233,7 +233,10 @@ struct AxisRecord
{ {
float min, default_, max; float min, default_, max;
get_coordinates (min, default_, max); get_coordinates (min, default_, max);
return TripleDistances (min, default_, max); return TripleDistances (
static_cast<double>(min),
static_cast<double>(default_),
static_cast<double>(max));
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const

View File

@ -102,9 +102,8 @@ struct glyph_variations_t
} }
bool is_composite_glyph = false; bool is_composite_glyph = false;
#ifdef HB_EXPERIMENTAL_API
is_composite_glyph = plan->composite_new_gids.has (new_gid); is_composite_glyph = plan->composite_new_gids.has (new_gid);
#endif
if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */, if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
iterator, &(plan->axes_old_index_tag_map), iterator, &(plan->axes_old_index_tag_map),
shared_indices, shared_tuples, shared_indices, shared_tuples,
@ -120,9 +119,7 @@ struct glyph_variations_t
{ {
unsigned count = plan->new_to_old_gid_list.length; unsigned count = plan->new_to_old_gid_list.length;
bool iup_optimize = false; bool iup_optimize = false;
#ifdef HB_EXPERIMENTAL_API
iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS; iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
#endif
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ {
hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first; hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;

View File

@ -337,9 +337,10 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
inline bool inline bool
hb_resolve_graph_overflows (hb_tag_t table_tag, hb_resolve_graph_overflows (hb_tag_t table_tag,
unsigned max_rounds , unsigned max_rounds ,
bool recalculate_extensions, bool always_recalculate_extensions,
graph_t& sorted_graph /* IN/OUT */) graph_t& sorted_graph /* IN/OUT */)
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Repacking %c%c%c%c.", HB_UNTAG(table_tag));
sorted_graph.sort_shortest_distance (); sorted_graph.sort_shortest_distance ();
if (sorted_graph.in_error ()) if (sorted_graph.in_error ())
{ {
@ -351,12 +352,12 @@ hb_resolve_graph_overflows (hb_tag_t table_tag,
if (!will_overflow) if (!will_overflow)
return true; return true;
bool is_gsub_or_gpos = (table_tag == HB_OT_TAG_GPOS || table_tag == HB_OT_TAG_GSUB);
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph); graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
if ((table_tag == HB_OT_TAG_GPOS if (is_gsub_or_gpos && will_overflow)
|| table_tag == HB_OT_TAG_GSUB)
&& will_overflow)
{ {
if (recalculate_extensions) DEBUG_MSG (SUBSET_REPACK, nullptr, "Applying GSUB/GPOS repacking specializations.");
if (always_recalculate_extensions)
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
if (!_presplit_subtables_if_needed (ext_context)) { if (!_presplit_subtables_if_needed (ext_context)) {
@ -412,6 +413,13 @@ hb_resolve_graph_overflows (hb_tag_t table_tag,
if (graph::will_overflow (sorted_graph)) if (graph::will_overflow (sorted_graph))
{ {
if (is_gsub_or_gpos && !always_recalculate_extensions) {
// If this a GSUB/GPOS table and we didn't try to extension promotion and table splitting then
// as a last ditch effort, re-run the repacker with it enabled.
DEBUG_MSG (SUBSET_REPACK, nullptr, "Failed to find a resolution. Re-running with extension promotion and table splitting enabled.");
return hb_resolve_graph_overflows (table_tag, max_rounds, true, sorted_graph);
}
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
return false; return false;
} }

View File

@ -82,7 +82,9 @@ struct hb_set_digest_bits_pattern_t
void init () { mask = 0; } void init () { mask = 0; }
void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; } static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; }
void union_ (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
void add (hb_codepoint_t g) { mask |= mask_for (g); } void add (hb_codepoint_t g) { mask |= mask_for (g); }
@ -129,11 +131,14 @@ struct hb_set_digest_bits_pattern_t
bool may_have (hb_codepoint_t g) const bool may_have (hb_codepoint_t g) const
{ return mask & mask_for (g); } { return mask & mask_for (g); }
bool operator [] (hb_codepoint_t g) const
{ return may_have (g); }
private: private:
static mask_t mask_for (hb_codepoint_t g) static mask_t mask_for (hb_codepoint_t g)
{ return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); } { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
mask_t mask; mask_t mask = 0;
}; };
template <typename head_t, typename tail_t> template <typename head_t, typename tail_t>
@ -145,10 +150,12 @@ struct hb_set_digest_combiner_t
tail.init (); tail.init ();
} }
void add (const hb_set_digest_combiner_t &o) static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; }
void union_ (const hb_set_digest_combiner_t &o)
{ {
head.add (o.head); head.union_ (o.head);
tail.add (o.tail); tail.union_(o.tail);
} }
void add (hb_codepoint_t g) void add (hb_codepoint_t g)
@ -188,6 +195,9 @@ struct hb_set_digest_combiner_t
return head.may_have (g) && tail.may_have (g); return head.may_have (g) && tail.may_have (g);
} }
bool operator [] (hb_codepoint_t g) const
{ return may_have (g); }
private: private:
head_t head; head_t head;
tail_t tail; tail_t tail;

View File

@ -86,7 +86,7 @@ struct hb_sparseset_t
uint32_t hash () const { return s.hash (); } uint32_t hash () const { return s.hash (); }
void add (hb_codepoint_t g) { s.add (g); } void add (hb_codepoint_t g) { s.add (g); }
bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); } bool add_range (hb_codepoint_t first, hb_codepoint_t last) { return s.add_range (first, last); }
template <typename T> template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))

View File

@ -115,7 +115,7 @@ struct str_encoder_t
encode_byte (OpCode_BCD); encode_byte (OpCode_BCD);
// Based on: // Based on:
// https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294 // https://github.com/fonttools/fonttools/blob/0738c41dfbcbc213ab9263f486ef0cccc6eb5ce5/Lib/fontTools/misc/psCharStrings.py#L267-L316
char buf[16]; char buf[16];
/* FontTools has the following comment: /* FontTools has the following comment:
@ -133,6 +133,10 @@ struct str_encoder_t
(void) hb_uselocale (((void) freelocale (clocale), oldlocale)); (void) hb_uselocale (((void) freelocale (clocale), oldlocale));
char *s = buf; char *s = buf;
size_t len;
char *comma = strchr (s, ',');
if (comma) // Comma for some European locales in case no uselocale available.
*comma = '.';
if (s[0] == '0' && s[1] == '.') if (s[0] == '0' && s[1] == '.')
s++; s++;
else if (s[0] == '-' && s[1] == '0' && s[2] == '.') else if (s[0] == '-' && s[1] == '0' && s[2] == '.')
@ -140,6 +144,45 @@ struct str_encoder_t
s[1] = '-'; s[1] = '-';
s++; s++;
} }
else if ((len = strlen (s)) > 3 && !strcmp (s + len - 3, "000"))
{
unsigned exponent = len - 3;
char *s2 = s + exponent - 1;
while (*s2 == '0' && exponent > 1)
{
s2--;
exponent++;
}
snprintf (s2 + 1, sizeof (buf) - (s2 + 1 - buf), "E%u", exponent);
}
else
{
char *dot = strchr (s, '.');
char *e = strchr (s, 'E');
if (dot && e)
{
memmove (dot, dot + 1, e - (dot + 1));
int exponent = atoi (e + 1);
int new_exponent = exponent - (e - (dot + 1));
if (new_exponent == 1)
{
e[-1] = '0';
e[0] = '\0';
}
else
snprintf (e - 1, sizeof (buf) - (e - 1 - buf), "E%d", new_exponent);
}
}
if ((s[0] == '.' && s[1] == '0') || (s[0] == '-' && s[1] == '.' && s[2] == '0'))
{
int sign = s[0] == '-';
char *s2 = s + sign + 1;
while (*s2 == '0')
s2++;
len = strlen (s2);
memmove (s + sign, s2, len);
snprintf (s + sign + len, sizeof (buf) - (s + sign + len - buf), "E-%u", (unsigned) (strlen (s + sign) - 1));
}
hb_vector_t<char> nibbles; hb_vector_t<char> nibbles;
while (*s) while (*s)
{ {
@ -155,20 +198,22 @@ struct str_encoder_t
{ {
s++; s++;
nibbles.push (0x0C); // E- nibbles.push (0x0C); // E-
continue; } else {
if (c2 == '+')
s++;
nibbles.push (0x0B); // E
} }
if (c2 == '+') if (*s == '0')
s++; s++;
nibbles.push (0x0B); // E
continue; continue;
} }
case '.': case ',': // Comma for some European locales in case no uselocale available. case '.':
nibbles.push (0x0A); // . nibbles.push (0x0A); // .
continue; continue;
case '-': case '-':
nibbles.push (0x0E); // . nibbles.push (0x0E); // -
continue; continue;
} }

View File

@ -666,6 +666,9 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
bool bool
OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
{ {
if (c->plan->normalized_coords && !c->plan->all_axes_pinned)
fprintf (stdout, "warning: CFF partial instancing is not supported.\n");
cff2_subset_plan cff2_plan; cff2_subset_plan cff2_plan;
if (unlikely (!cff2_plan.create (*this, c->plan))) return false; if (unlikely (!cff2_plan.create (*this, c->plan))) return false;

View File

@ -446,7 +446,7 @@ hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
for (unsigned i = 0; i < axis_count; i++) for (unsigned i = 0; i < axis_count; i++)
{ {
hb_tag_t axis_tag = axis_infos[i].tag; hb_tag_t axis_tag = axis_infos[i].tag;
float default_val = axis_infos[i].default_value; double default_val = (double) axis_infos[i].default_value;
if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val))) if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
{ {
hb_free (axis_infos); hb_free (axis_infos);
@ -481,7 +481,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false; return false;
float default_val = axis_info.default_value; double default_val = (double) axis_info.default_value;
return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)); return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
} }
@ -511,11 +511,10 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false; return false;
float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value); double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value);
return input->axes_location.set (axis_tag, Triple (val, val, val)); return input->axes_location.set (axis_tag, Triple (val, val, val));
} }
#ifdef HB_EXPERIMENTAL_API
/** /**
* hb_subset_input_set_axis_range: (skip) * hb_subset_input_set_axis_range: (skip)
* @input: a #hb_subset_input_t object. * @input: a #hb_subset_input_t object.
@ -538,7 +537,7 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
* *
* Return value: `true` if success, `false` otherwise * Return value: `true` if success, `false` otherwise
* *
* XSince: EXPERIMENTAL * Since: 8.5.0
**/ **/
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_set_axis_range (hb_subset_input_t *input, hb_subset_input_set_axis_range (hb_subset_input_t *input,
@ -562,7 +561,7 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value); float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value); float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
float new_default_val = hb_clamp(def, new_min_val, new_max_val); float new_default_val = hb_clamp(def, new_min_val, new_max_val);
return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val)); return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val));
} }
/** /**
@ -577,7 +576,7 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
* *
* Return value: `true` if a range has been set for this axis tag, `false` otherwise. * Return value: `true` if a range has been set for this axis tag, `false` otherwise.
* *
* XSince: EXPERIMENTAL * Since: 8.5.0
**/ **/
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_get_axis_range (hb_subset_input_t *input, hb_subset_input_get_axis_range (hb_subset_input_t *input,
@ -598,7 +597,6 @@ hb_subset_input_get_axis_range (hb_subset_input_t *input,
return true; return true;
} }
#endif #endif
#endif
/** /**
* hb_subset_preprocess: * hb_subset_preprocess:
@ -746,5 +744,4 @@ hb_subset_input_override_name_table (hb_subset_input_t *input,
input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes); input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
return true; return true;
} }
#endif #endif

View File

@ -38,7 +38,7 @@ static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_
const hb_array_t<const int> x_deltas, const hb_array_t<const int> x_deltas,
const hb_array_t<const int> y_deltas, const hb_array_t<const int> y_deltas,
hb_set_t& forced_set, /* OUT */ hb_set_t& forced_set, /* OUT */
float tolerance = 0.f) double tolerance = 0.0)
{ {
unsigned len = contour_points.length; unsigned len = contour_points.length;
unsigned next_i = 0; unsigned next_i = 0;
@ -47,28 +47,28 @@ static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_
unsigned last_i = (len + i -1) % len; unsigned last_i = (len + i -1) % len;
for (unsigned j = 0; j < 2; j++) for (unsigned j = 0; j < 2; j++)
{ {
float cj, lcj, ncj; double cj, lcj, ncj;
int dj, ldj, ndj; int dj, ldj, ndj;
if (j == 0) if (j == 0)
{ {
cj = contour_points.arrayZ[i].x; cj = static_cast<double> (contour_points.arrayZ[i].x);
dj = x_deltas.arrayZ[i]; dj = x_deltas.arrayZ[i];
lcj = contour_points.arrayZ[last_i].x; lcj = static_cast<double> (contour_points.arrayZ[last_i].x);
ldj = x_deltas.arrayZ[last_i]; ldj = x_deltas.arrayZ[last_i];
ncj = contour_points.arrayZ[next_i].x; ncj = static_cast<double> (contour_points.arrayZ[next_i].x);
ndj = x_deltas.arrayZ[next_i]; ndj = x_deltas.arrayZ[next_i];
} }
else else
{ {
cj = contour_points.arrayZ[i].y; cj = static_cast<double> (contour_points.arrayZ[i].y);
dj = y_deltas.arrayZ[i]; dj = y_deltas.arrayZ[i];
lcj = contour_points.arrayZ[last_i].y; lcj = static_cast<double> (contour_points.arrayZ[last_i].y);
ldj = y_deltas.arrayZ[last_i]; ldj = y_deltas.arrayZ[last_i];
ncj = contour_points.arrayZ[next_i].y; ncj = static_cast<double> (contour_points.arrayZ[next_i].y);
ndj = y_deltas.arrayZ[next_i]; ndj = y_deltas.arrayZ[next_i];
} }
float c1, c2; double c1, c2;
int d1, d2; int d1, d2;
if (lcj <= ncj) if (lcj <= ncj)
{ {
@ -180,8 +180,8 @@ static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points
const contour_point_t& p1, const contour_point_t& p2, const contour_point_t& p1, const contour_point_t& p2,
int p1_dx, int p2_dx, int p1_dx, int p2_dx,
int p1_dy, int p2_dy, int p1_dy, int p2_dy,
hb_vector_t<float>& interp_x_deltas, /* OUT */ hb_vector_t<double>& interp_x_deltas, /* OUT */
hb_vector_t<float>& interp_y_deltas /* OUT */) hb_vector_t<double>& interp_y_deltas /* OUT */)
{ {
unsigned n = contour_points.length; unsigned n = contour_points.length;
if (unlikely (!interp_x_deltas.resize (n, false) || if (unlikely (!interp_x_deltas.resize (n, false) ||
@ -190,20 +190,20 @@ static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points
for (unsigned j = 0; j < 2; j++) for (unsigned j = 0; j < 2; j++)
{ {
float x1, x2, d1, d2; double x1, x2, d1, d2;
float *out; double *out;
if (j == 0) if (j == 0)
{ {
x1 = p1.x; x1 = static_cast<double> (p1.x);
x2 = p2.x; x2 = static_cast<double> (p2.x);
d1 = p1_dx; d1 = p1_dx;
d2 = p2_dx; d2 = p2_dx;
out = interp_x_deltas.arrayZ; out = interp_x_deltas.arrayZ;
} }
else else
{ {
x1 = p1.y; x1 = static_cast<double> (p1.y);
x2 = p2.y; x2 = static_cast<double> (p2.y);
d1 = p1_dy; d1 = p1_dy;
d2 = p2_dy; d2 = p2_dy;
out = interp_y_deltas.arrayZ; out = interp_y_deltas.arrayZ;
@ -219,7 +219,7 @@ static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points
else else
{ {
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
out[i] = 0.f; out[i] = 0.0;
} }
continue; continue;
} }
@ -230,11 +230,11 @@ static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points
hb_swap (d1, d2); hb_swap (d1, d2);
} }
float scale = (d2 - d1) / (x2 - x1); double scale = (d2 - d1) / (x2 - x1);
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
{ {
float x = j == 0 ? contour_points.arrayZ[i].x : contour_points.arrayZ[i].y; double x = (j == 0 ? static_cast<double> (contour_points.arrayZ[i].x) : static_cast<double> (contour_points.arrayZ[i].y));
float d; double d;
if (x <= x1) if (x <= x1)
d = d1; d = d1;
else if (x >= x2) else if (x >= x2)
@ -254,9 +254,9 @@ static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour
const contour_point_t& p1, const contour_point_t& p2, const contour_point_t& p1, const contour_point_t& p2,
int p1_dx, int p2_dx, int p1_dx, int p2_dx,
int p1_dy, int p2_dy, int p1_dy, int p2_dy,
float tolerance) double tolerance)
{ {
hb_vector_t<float> interp_x_deltas, interp_y_deltas; hb_vector_t<double> interp_x_deltas, interp_y_deltas;
if (!_iup_segment (contour_points, x_deltas, y_deltas, if (!_iup_segment (contour_points, x_deltas, y_deltas,
p1, p2, p1_dx, p2_dx, p1_dy, p2_dy, p1, p2, p1_dx, p2_dx, p1_dy, p2_dy,
interp_x_deltas, interp_y_deltas)) interp_x_deltas, interp_y_deltas))
@ -266,10 +266,10 @@ static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour
for (unsigned i = 0; i < num; i++) for (unsigned i = 0; i < num; i++)
{ {
float dx = x_deltas.arrayZ[i] - interp_x_deltas.arrayZ[i]; double dx = static_cast<double> (x_deltas.arrayZ[i]) - interp_x_deltas.arrayZ[i];
float dy = y_deltas.arrayZ[i] - interp_y_deltas.arrayZ[i]; double dy = static_cast<double> (y_deltas.arrayZ[i]) - interp_y_deltas.arrayZ[i];
if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance) if (sqrt (dx * dx + dy * dy) > tolerance)
return false; return false;
} }
return true; return true;
@ -279,7 +279,7 @@ static bool _iup_contour_optimize_dp (const contour_point_vector_t& contour_poin
const hb_vector_t<int>& x_deltas, const hb_vector_t<int>& x_deltas,
const hb_vector_t<int>& y_deltas, const hb_vector_t<int>& y_deltas,
const hb_set_t& forced_set, const hb_set_t& forced_set,
float tolerance, double tolerance,
unsigned lookback, unsigned lookback,
hb_vector_t<unsigned>& costs, /* OUT */ hb_vector_t<unsigned>& costs, /* OUT */
hb_vector_t<int>& chain /* OUT */) hb_vector_t<int>& chain /* OUT */)
@ -333,7 +333,7 @@ static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> conto
const hb_array_t<const int> x_deltas, const hb_array_t<const int> x_deltas,
const hb_array_t<const int> y_deltas, const hb_array_t<const int> y_deltas,
hb_array_t<bool> opt_indices, /* OUT */ hb_array_t<bool> opt_indices, /* OUT */
float tolerance = 0.f) double tolerance = 0.0)
{ {
unsigned n = contour_points.length; unsigned n = contour_points.length;
if (opt_indices.length != n || if (opt_indices.length != n ||
@ -346,7 +346,7 @@ static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> conto
{ {
int dx = x_deltas.arrayZ[i]; int dx = x_deltas.arrayZ[i];
int dy = y_deltas.arrayZ[i]; int dy = y_deltas.arrayZ[i];
if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance) if (sqrt ((double) dx * dx + (double) dy * dy) > tolerance)
{ {
all_within_tolerance = false; all_within_tolerance = false;
break; break;
@ -443,11 +443,11 @@ static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> conto
unsigned contour_point_size = hb_static_size (contour_point_t); unsigned contour_point_size = hb_static_size (contour_point_t);
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
{ {
hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (float)); hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (float)); hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (float)); hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (float)); hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size); hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size);
hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size); hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size);
@ -496,7 +496,7 @@ bool iup_delta_optimize (const contour_point_vector_t& contour_points,
const hb_vector_t<int>& x_deltas, const hb_vector_t<int>& x_deltas,
const hb_vector_t<int>& y_deltas, const hb_vector_t<int>& y_deltas,
hb_vector_t<bool>& opt_indices, /* OUT */ hb_vector_t<bool>& opt_indices, /* OUT */
float tolerance) double tolerance)
{ {
if (!opt_indices.resize (contour_points.length)) if (!opt_indices.resize (contour_points.length))
return false; return false;

View File

@ -32,6 +32,6 @@ HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_point
const hb_vector_t<int>& x_deltas, const hb_vector_t<int>& x_deltas,
const hb_vector_t<int>& y_deltas, const hb_vector_t<int>& y_deltas,
hb_vector_t<bool>& opt_indices, /* OUT */ hb_vector_t<bool>& opt_indices, /* OUT */
float tolerance = 0.f); double tolerance = 0.0);
#endif /* HB_SUBSET_INSTANCER_IUP_HH */ #endif /* HB_SUBSET_INSTANCER_IUP_HH */

View File

@ -32,17 +32,17 @@
* This should be safe. * This should be safe.
*/ */
constexpr static float EPSILON = 1.f / (1 << 14); constexpr static double EPSILON = 1.0 / (1 << 14);
constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14); constexpr static double MAX_F2DOT14 = double (0x7FFF) / (1 << 14);
static inline Triple _reverse_negate(const Triple &v) static inline Triple _reverse_negate(const Triple &v)
{ return {-v.maximum, -v.middle, -v.minimum}; } { return {-v.maximum, -v.middle, -v.minimum}; }
static inline float supportScalar (float coord, const Triple &tent) static inline double supportScalar (double coord, const Triple &tent)
{ {
/* Copied from VarRegionAxis::evaluate() */ /* Copied from VarRegionAxis::evaluate() */
float start = tent.minimum, peak = tent.middle, end = tent.maximum; double start = tent.minimum, peak = tent.middle, end = tent.maximum;
if (unlikely (start > peak || peak > end)) if (unlikely (start > peak || peak > end))
return 1.; return 1.;
@ -62,20 +62,20 @@ static inline float supportScalar (float coord, const Triple &tent)
return (end - coord) / (end - peak); return (end - coord) / (end - peak);
} }
static inline result_t static inline rebase_tent_result_t
_solve (Triple tent, Triple axisLimit, bool negative = false) _solve (Triple tent, Triple axisLimit, bool negative = false)
{ {
float axisMin = axisLimit.minimum; double axisMin = axisLimit.minimum;
float axisDef = axisLimit.middle; double axisDef = axisLimit.middle;
float axisMax = axisLimit.maximum; double axisMax = axisLimit.maximum;
float lower = tent.minimum; double lower = tent.minimum;
float peak = tent.middle; double peak = tent.middle;
float upper = tent.maximum; double upper = tent.maximum;
// Mirror the problem such that axisDef <= peak // Mirror the problem such that axisDef <= peak
if (axisDef > peak) if (axisDef > peak)
{ {
result_t vec = _solve (_reverse_negate (tent), rebase_tent_result_t vec = _solve (_reverse_negate (tent),
_reverse_negate (axisLimit), _reverse_negate (axisLimit),
!negative); !negative);
@ -98,7 +98,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
* axisMin axisDef axisMax lower upper * axisMin axisDef axisMax lower upper
*/ */
if (axisMax <= lower && axisMax < peak) if (axisMax <= lower && axisMax < peak)
return result_t{}; // No overlap return rebase_tent_result_t{}; // No overlap
/* case 2: Only the peak and outermost bound fall outside the new limit; /* case 2: Only the peak and outermost bound fall outside the new limit;
* we keep the deltaset, update peak and outermost bound and scale deltas * we keep the deltaset, update peak and outermost bound and scale deltas
@ -130,10 +130,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
*/ */
if (axisMax < peak) if (axisMax < peak)
{ {
float mult = supportScalar (axisMax, tent); double mult = supportScalar (axisMax, tent);
tent = Triple{lower, axisMax, axisMax}; tent = Triple{lower, axisMax, axisMax};
result_t vec = _solve (tent, axisLimit); rebase_tent_result_t vec = _solve (tent, axisLimit);
for (auto &p : vec) for (auto &p : vec)
p = hb_pair (p.first * mult, p.second); p = hb_pair (p.first * mult, p.second);
@ -143,13 +143,13 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// lower <= axisDef <= peak <= axisMax // lower <= axisDef <= peak <= axisMax
float gain = supportScalar (axisDef, tent); double gain = supportScalar (axisDef, tent);
result_t out {hb_pair (gain, Triple{})}; rebase_tent_result_t out {hb_pair (gain, Triple{})};
// First, the positive side // First, the positive side
// outGain is the scalar of axisMax at the tent. // outGain is the scalar of axisMax at the tent.
float outGain = supportScalar (axisMax, tent); double outGain = supportScalar (axisMax, tent);
/* Case 3a: Gain is more than outGain. The tent down-slope crosses /* Case 3a: Gain is more than outGain. The tent down-slope crosses
* the axis into negative. We have to split it into multiples. * the axis into negative. We have to split it into multiples.
@ -173,10 +173,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Note that this is the branch taken if both gain and outGain are 0. // Note that this is the branch taken if both gain and outGain are 0.
// Crossing point on the axis. // Crossing point on the axis.
float crossing = peak + (1 - gain) * (upper - peak); double crossing = peak + (1 - gain) * (upper - peak);
Triple loc{hb_max (lower, axisDef), peak, crossing}; Triple loc{hb_max (lower, axisDef), peak, crossing};
float scalar = 1.f; double scalar = 1.0;
// The part before the crossing point. // The part before the crossing point.
out.push (hb_pair (scalar - gain, loc)); out.push (hb_pair (scalar - gain, loc));
@ -191,7 +191,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (upper >= axisMax) if (upper >= axisMax)
{ {
Triple loc {crossing, axisMax, axisMax}; Triple loc {crossing, axisMax, axisMax};
float scalar = outGain; double scalar = outGain;
out.push (hb_pair (scalar - gain, loc)); out.push (hb_pair (scalar - gain, loc));
} }
@ -221,11 +221,11 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Downslope. // Downslope.
Triple loc1 {crossing, upper, axisMax}; Triple loc1 {crossing, upper, axisMax};
float scalar1 = 0.f; double scalar1 = 0.0;
// Eternity justify. // Eternity justify.
Triple loc2 {upper, axisMax, axisMax}; Triple loc2 {upper, axisMax, axisMax};
float scalar2 = 0.f; double scalar2 = 0.0;
out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2)); out.push (hb_pair (scalar2 - gain, loc2));
@ -254,11 +254,11 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
* | | newUpper * | | newUpper
* axisDef axisMax * axisDef axisMax
*/ */
float newUpper = peak + (1 - gain) * (upper - peak); double newUpper = peak + (1 - gain) * (upper - peak);
assert (axisMax <= newUpper); // Because outGain > gain assert (axisMax <= newUpper); // Because outGain > gain
/* Disabled because ots doesn't like us: /* Disabled because ots doesn't like us:
* https://github.com/fonttools/fonttools/issues/3350 */ * https://github.com/fonttools/fonttools/issues/3350 */
if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2)) if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2))
{ {
upper = newUpper; upper = newUpper;
@ -270,7 +270,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
} }
Triple loc {hb_max (axisDef, lower), peak, upper}; Triple loc {hb_max (axisDef, lower), peak, upper};
float scalar = 1.f; double scalar = 1.0;
out.push (hb_pair (scalar - gain, loc)); out.push (hb_pair (scalar - gain, loc));
} }
@ -294,10 +294,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
else else
{ {
Triple loc1 {hb_max (axisDef, lower), peak, axisMax}; Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
float scalar1 = 1.f; double scalar1 = 1.0;
Triple loc2 {peak, axisMax, axisMax}; Triple loc2 {peak, axisMax, axisMax};
float scalar2 = outGain; double scalar2 = outGain;
out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar1 - gain, loc1));
// Don't add a dirac delta! // Don't add a dirac delta!
@ -325,7 +325,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (lower <= axisMin) if (lower <= axisMin)
{ {
Triple loc {axisMin, axisMin, axisDef}; Triple loc {axisMin, axisMin, axisDef};
float scalar = supportScalar (axisMin, tent); double scalar = supportScalar (axisMin, tent);
out.push (hb_pair (scalar - gain, loc)); out.push (hb_pair (scalar - gain, loc));
} }
@ -353,11 +353,11 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Downslope. // Downslope.
Triple loc1 {axisMin, lower, axisDef}; Triple loc1 {axisMin, lower, axisDef};
float scalar1 = 0.f; double scalar1 = 0.0;
// Eternity justify. // Eternity justify.
Triple loc2 {axisMin, axisMin, lower}; Triple loc2 {axisMin, axisMin, lower};
float scalar2 = 0.f; double scalar2 = 0.0;
out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2)); out.push (hb_pair (scalar2 - gain, loc2));
@ -369,19 +369,19 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
static inline TripleDistances _reverse_triple_distances (const TripleDistances &v) static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
{ return TripleDistances (v.positive, v.negative); } { return TripleDistances (v.positive, v.negative); }
float renormalizeValue (float v, const Triple &triple, double renormalizeValue (double v, const Triple &triple,
const TripleDistances &triple_distances, bool extrapolate) const TripleDistances &triple_distances, bool extrapolate)
{ {
float lower = triple.minimum, def = triple.middle, upper = triple.maximum; double lower = triple.minimum, def = triple.middle, upper = triple.maximum;
assert (lower <= def && def <= upper); assert (lower <= def && def <= upper);
if (!extrapolate) if (!extrapolate)
v = hb_max (hb_min (v, upper), lower); v = hb_max (hb_min (v, upper), lower);
if (v == def) if (v == def)
return 0.f; return 0.0;
if (def < 0.f) if (def < 0.0)
return -renormalizeValue (-v, _reverse_negate (triple), return -renormalizeValue (-v, _reverse_negate (triple),
_reverse_triple_distances (triple_distances), extrapolate); _reverse_triple_distances (triple_distances), extrapolate);
@ -390,14 +390,14 @@ float renormalizeValue (float v, const Triple &triple,
return (v - def) / (upper - def); return (v - def) / (upper - def);
/* v < def */ /* v < def */
if (lower >= 0.f) if (lower >= 0.0)
return (v - def) / (def - lower); return (v - def) / (def - lower);
/* lower < 0 and v < default */ /* lower < 0 and v < default */
float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
float v_distance; double v_distance;
if (v >= 0.f) if (v >= 0.0)
v_distance = (def - v) * triple_distances.positive; v_distance = (def - v) * triple_distances.positive;
else else
v_distance = (-v) * triple_distances.negative + triple_distances.positive * def; v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
@ -405,18 +405,18 @@ float renormalizeValue (float v, const Triple &triple,
return (-v_distance) /total_distance; return (-v_distance) /total_distance;
} }
result_t rebase_tent_result_t
rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances) rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
{ {
assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f); assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0);
assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f); assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0);
assert (tent.middle != 0.f); assert (tent.middle != 0.0);
result_t sols = _solve (tent, axisLimit); rebase_tent_result_t sols = _solve (tent, axisLimit);
auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); }; auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
result_t out; rebase_tent_result_t out;
for (auto &p : sols) for (auto &p : sols)
{ {
if (!p.first) continue; if (!p.first) continue;

View File

@ -30,24 +30,24 @@
/* pre-normalized distances */ /* pre-normalized distances */
struct TripleDistances struct TripleDistances
{ {
TripleDistances (): negative (1.f), positive (1.f) {} TripleDistances (): negative (1.0), positive (1.0) {}
TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {} TripleDistances (double neg_, double pos_): negative (neg_), positive (pos_) {}
TripleDistances (float min, float default_, float max) TripleDistances (double min, double default_, double max)
{ {
negative = default_ - min; negative = default_ - min;
positive = max - default_; positive = max - default_;
} }
float negative; double negative;
float positive; double positive;
}; };
struct Triple { struct Triple {
Triple () : Triple () :
minimum (0.f), middle (0.f), maximum (0.f) {} minimum (0.0), middle (0.0), maximum (0.0) {}
Triple (float minimum_, float middle_, float maximum_) : Triple (double minimum_, double middle_, double maximum_) :
minimum (minimum_), middle (middle_), maximum (maximum_) {} minimum (minimum_), middle (middle_), maximum (maximum_) {}
bool operator == (const Triple &o) const bool operator == (const Triple &o) const
@ -63,7 +63,7 @@ struct Triple {
bool is_point () const bool is_point () const
{ return minimum == middle && middle == maximum; } { return minimum == middle && middle == maximum; }
bool contains (float point) const bool contains (double point) const
{ return minimum <= point && point <= maximum; } { return minimum <= point && point <= maximum; }
/* from hb_array_t hash ()*/ /* from hb_array_t hash ()*/
@ -82,18 +82,18 @@ struct Triple {
} }
float minimum; double minimum;
float middle; double middle;
float maximum; double maximum;
}; };
using result_item_t = hb_pair_t<float, Triple>; using rebase_tent_result_item_t = hb_pair_t<double, Triple>;
using result_t = hb_vector_t<result_item_t>; using rebase_tent_result_t = hb_vector_t<rebase_tent_result_item_t>;
/* renormalize a normalized value v to the range of an axis, /* renormalize a normalized value v to the range of an axis,
* considering the prenormalized distances as well as the new axis limits. * considering the prenormalized distances as well as the new axis limits.
* Ported from fonttools */ * Ported from fonttools */
HB_INTERNAL float renormalizeValue (float v, const Triple &triple, HB_INTERNAL double renormalizeValue (double v, const Triple &triple,
const TripleDistances &triple_distances, const TripleDistances &triple_distances,
bool extrapolate = true); bool extrapolate = true);
/* Given a tuple (lower,peak,upper) "tent" and new axis limits /* Given a tuple (lower,peak,upper) "tent" and new axis limits
@ -107,6 +107,8 @@ HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
* If tent value is Triple{}, that is a special deltaset that should * If tent value is Triple{}, that is a special deltaset that should
* be always-enabled (called "gain"). * be always-enabled (called "gain").
*/ */
HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances); HB_INTERNAL rebase_tent_result_t rebase_tent (Triple tent,
Triple axisLimit,
TripleDistances axis_triple_distances);
#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */ #endif /* HB_SUBSET_INSTANCER_SOLVER_HH */

View File

@ -102,6 +102,12 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const
//active layers/palettes we'd like to retain //active layers/palettes we'd like to retain
HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers) HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes) HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
//colrv1 varstore retained varidx mapping
HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, colrv1_varstore_inner_maps)
//colrv1 retained varidx -> (new varidx, delta) mapping
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), colrv1_variation_idx_delta_map)
//colrv1 retained new delta set index -> new varidx mapping
HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_new_deltaset_idx_varidx_map)
//Old layout item variation index -> (New varidx, delta) mapping //Old layout item variation index -> (New varidx, delta) mapping
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map) HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
@ -144,7 +150,7 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vec
HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids) HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids)
//Old BASE item variation index -> (New varidx, 0) mapping //Old BASE item variation index -> (New varidx, 0) mapping
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map) HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map)
//BASE table varstore retained varidx mapping //BASE table varstore retained varidx mapping
HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps) HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps)

View File

@ -398,13 +398,56 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
return font; return font;
} }
static inline void
_remap_variation_indices (const OT::ItemVariationStore &var_store,
const hb_set_t &variation_indices,
const hb_vector_t<int>& normalized_coords,
bool calculate_delta, /* not pinned at default */
bool no_variations, /* all axes pinned */
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */)
{
if (&var_store == &Null (OT::ItemVariationStore)) return;
unsigned subtable_count = var_store.get_sub_table_count ();
float *store_cache = var_store.create_cache ();
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (variation_indices.get_min ()) >> 16;
for (unsigned idx : variation_indices)
{
int delta = 0;
if (calculate_delta)
delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
normalized_coords.length, store_cache));
if (no_variations)
{
variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
continue;
}
uint16_t major = idx >> 16;
if (major >= subtable_count) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
var_store.destroy_cache (store_cache);
}
static inline void static inline void
_collect_layout_variation_indices (hb_subset_plan_t* plan) _collect_layout_variation_indices (hb_subset_plan_t* plan)
{ {
hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> (); hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> (); hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
if (!gdef->has_data ()) if (!gdef->has_data () || !gdef->has_var_store ())
{ {
gdef.destroy (); gdef.destroy ();
gpos.destroy (); gpos.destroy ();
@ -420,13 +463,13 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
if (hb_ot_layout_has_positioning (plan->source)) if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c); gpos->collect_variation_indices (&c);
gdef->remap_layout_variation_indices (&varidx_set, _remap_variation_indices (gdef->get_var_store (),
plan->normalized_coords, varidx_set, plan->normalized_coords,
!plan->pinned_at_default, !plan->pinned_at_default,
plan->all_axes_pinned, plan->all_axes_pinned,
&plan->layout_variation_idx_delta_map); plan->layout_variation_idx_delta_map);
unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0; unsigned subtable_count = gdef->get_var_store ().get_sub_table_count ();
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps); _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
gdef.destroy (); gdef.destroy ();
@ -434,31 +477,6 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
} }
#ifndef HB_NO_BASE #ifndef HB_NO_BASE
/* used by BASE table only, delta is always set to 0 in the output map */
static inline void
_remap_variation_indices (const hb_set_t& indices,
unsigned subtable_count,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& variation_idx_delta_map /* OUT */)
{
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (indices.get_min ()) >> 16;
for (unsigned idx : indices)
{
uint16_t major = idx >> 16;
if (major >= subtable_count) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, 0));
++new_minor;
last_major = major;
}
}
static inline void static inline void
_collect_base_variation_indices (hb_subset_plan_t* plan) _collect_base_variation_indices (hb_subset_plan_t* plan)
{ {
@ -471,12 +489,20 @@ _collect_base_variation_indices (hb_subset_plan_t* plan)
hb_set_t varidx_set; hb_set_t varidx_set;
base->collect_variation_indices (plan, varidx_set); base->collect_variation_indices (plan, varidx_set);
unsigned subtable_count = base->get_var_store ().get_sub_table_count (); const OT::ItemVariationStore &var_store = base->get_var_store ();
base.destroy (); unsigned subtable_count = var_store.get_sub_table_count ();
_remap_variation_indices (varidx_set, subtable_count, plan->base_variation_idx_map); _remap_variation_indices (var_store, varidx_set,
plan->normalized_coords,
!plan->pinned_at_default,
plan->all_axes_pinned,
plan->base_variation_idx_map);
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps); _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
base.destroy ();
} }
#endif #endif
#endif #endif
@ -489,12 +515,43 @@ _cmap_closure (hb_face_t *face,
cmap.table->closure_glyphs (unicodes, glyphset); cmap.table->closure_glyphs (unicodes, glyphset);
} }
static void _colr_closure (hb_face_t *face, static void
hb_map_t *layers_map, _remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
hb_map_t *palettes_map, const hb_set_t &delta_set_idxes,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map, /* IN/OUT */
hb_map_t &new_deltaset_idx_varidx_map /* OUT */)
{
if (!index_map.get_map_count ())
return;
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> delta_set_idx_delta_map;
unsigned new_delta_set_idx = 0;
for (unsigned delta_set_idx : delta_set_idxes)
{
unsigned var_idx = index_map.map (delta_set_idx);
unsigned new_varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
int delta = 0;
if (var_idx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
{
hb_pair_t<unsigned, int> *new_varidx_delta;
if (!variation_idx_delta_map.has (var_idx, &new_varidx_delta)) continue;
new_varidx = hb_first (*new_varidx_delta);
delta = hb_second (*new_varidx_delta);
}
new_deltaset_idx_varidx_map.set (new_delta_set_idx, new_varidx);
delta_set_idx_delta_map.set (delta_set_idx, hb_pair_t<unsigned, int> (new_delta_set_idx, delta));
new_delta_set_idx++;
}
variation_idx_delta_map = std::move (delta_set_idx_delta_map);
}
static void _colr_closure (hb_subset_plan_t* plan,
hb_set_t *glyphs_colred) hb_set_t *glyphs_colred)
{ {
OT::COLR::accelerator_t colr (face); OT::COLR::accelerator_t colr (plan->source);
if (!colr.is_valid ()) return; if (!colr.is_valid ()) return;
hb_set_t palette_indices, layer_indices; hb_set_t palette_indices, layer_indices;
@ -506,11 +563,43 @@ static void _colr_closure (hb_face_t *face,
glyphs_colred->union_ (glyphset_colrv0); glyphs_colred->union_ (glyphset_colrv0);
//closure for COLRv1 //closure for COLRv1
colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices); hb_set_t variation_indices, delta_set_indices;
colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices);
colr.closure_V0palette_indices (glyphs_colred, &palette_indices); colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
_remap_indexes (&layer_indices, layers_map); _remap_indexes (&layer_indices, &plan->colrv1_layers);
_remap_palette_indexes (&palette_indices, palettes_map); _remap_palette_indexes (&palette_indices, &plan->colr_palettes);
if (!colr.has_var_store () || !variation_indices) return;
const OT::ItemVariationStore &var_store = colr.get_var_store ();
// generated inner_maps is used by ItemVariationStore serialize(), which is subset only
unsigned subtable_count = var_store.get_sub_table_count ();
_generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps);
/* colr variation indices mapping during planning phase:
* generate colrv1_variation_idx_delta_map. When delta set index map is not
* included, it's a mapping from varIdx-> (new varIdx,delta). Otherwise, it's
* a mapping from old delta set idx-> (new delta set idx, delta). Mapping
* delta set indices is the same as gid mapping.
* Besides, we need to generate a delta set idx-> new var_idx map for updating
* delta set index map if exists. This map will be updated again after
* instancing. */
if (!plan->all_axes_pinned)
{
_remap_variation_indices (var_store,
variation_indices,
plan->normalized_coords,
false, /* no need to calculate delta for COLR during planning */
plan->all_axes_pinned,
plan->colrv1_variation_idx_delta_map);
if (colr.has_delta_set_index_map ())
_remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (),
delta_set_indices,
plan->colrv1_variation_idx_delta_map,
plan->colrv1_new_deltaset_idx_varidx_map);
}
} }
static inline void static inline void
@ -821,7 +910,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
hb_set_t cur_glyphset = plan->_glyphset_mathed; hb_set_t cur_glyphset = plan->_glyphset_mathed;
if (!drop_tables->has (HB_OT_TAG_COLR)) if (!drop_tables->has (HB_OT_TAG_COLR))
{ {
_colr_closure (plan->source, &plan->colrv1_layers, &plan->colr_palettes, &cur_glyphset); _colr_closure (plan, &cur_glyphset);
_remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
} }
@ -1016,9 +1105,9 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
normalized_default = seg_maps->map (normalized_default); normalized_default = seg_maps->map (normalized_default);
normalized_max = seg_maps->map (normalized_max); normalized_max = seg_maps->map (normalized_max);
} }
plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f), plan->axes_location.set (axis_tag, Triple (static_cast<double> (normalized_min / 16384.0),
static_cast<float> (normalized_default / 16384.f), static_cast<double> (normalized_default / 16384.0),
static_cast<float> (normalized_max / 16384.f))); static_cast<double> (normalized_max / 16384.0)));
if (normalized_default != 0) if (normalized_default != 0)
plan->pinned_at_default = false; plan->pinned_at_default = false;
@ -1145,11 +1234,9 @@ _get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points))) if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
return false; return false;
#ifdef HB_EXPERIMENTAL_API
/* composite new gids are only needed by iup delta optimization */ /* composite new gids are only needed by iup delta optimization */
if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ()) if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ())
plan->composite_new_gids.add (new_gid); plan->composite_new_gids.add (new_gid);
#endif
} }
return true; return true;
} }

View File

@ -73,11 +73,11 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* OS/2 will not be recalculated. * OS/2 will not be recalculated.
* @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
* substitution rules (GSUB). Since: 7.2.0. * substitution rules (GSUB). Since: 7.2.0.
* @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
* remaining gvar table's deltas. Since: 8.5.0
* @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
* to allow it to be used with incremental font transfer IFTB patches. Primarily, * to allow it to be used with incremental font transfer IFTB patches. Primarily,
* this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
* @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
* remaining gvar table's deltas. Since: EXPERIMENTAL
* *
* List of boolean properties that can be configured on the subset input. * List of boolean properties that can be configured on the subset input.
* *
@ -95,9 +95,9 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u, HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000400u,
#ifdef HB_EXPERIMENTAL_API #ifdef HB_EXPERIMENTAL_API
HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000400u, HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000800u,
HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000800u,
#endif #endif
} hb_subset_flags_t; } hb_subset_flags_t;
@ -188,7 +188,6 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
hb_tag_t axis_tag, hb_tag_t axis_tag,
float axis_value); float axis_value);
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_get_axis_range (hb_subset_input_t *input, hb_subset_input_get_axis_range (hb_subset_input_t *input,
hb_tag_t axis_tag, hb_tag_t axis_tag,
@ -204,6 +203,7 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
float axis_max_value, float axis_max_value,
float axis_def_value); float axis_def_value);
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_override_name_table (hb_subset_input_t *input, hb_subset_input_override_name_table (hb_subset_input_t *input,
hb_ot_name_id_t name_id, hb_ot_name_id_t name_id,
@ -212,7 +212,6 @@ hb_subset_input_override_name_table (hb_subset_input_t *input,
unsigned language_id, unsigned language_id,
const char *name_str, const char *name_str,
int str_len); int str_len);
#endif #endif
HB_EXTERN hb_face_t * HB_EXTERN hb_face_t *

View File

@ -47,7 +47,7 @@ HB_BEGIN_DECLS
* *
* The minor component of the library version available at compile-time. * The minor component of the library version available at compile-time.
*/ */
#define HB_VERSION_MINOR 4 #define HB_VERSION_MINOR 5
/** /**
* HB_VERSION_MICRO: * HB_VERSION_MICRO:
* *
@ -60,7 +60,7 @@ HB_BEGIN_DECLS
* *
* A string literal containing the library version available at compile-time. * A string literal containing the library version available at compile-time.
*/ */
#define HB_VERSION_STRING "8.4.0" #define HB_VERSION_STRING "8.5.0"
/** /**
* HB_VERSION_ATLEAST: * HB_VERSION_ATLEAST: