nesting_level_left++;
}
+ bool lookup_limit_exceeded ()
+ { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
bool should_visit_lookup (unsigned int lookup_index)
{
+ if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+ return false;
+
if (is_lookup_done (lookup_index))
return false;
+
done_lookups->set (lookup_index, glyphs->get_population ());
return true;
}
recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
debug_depth (0),
- done_lookups (done_lookups_) {}
+ done_lookups (done_lookups_),
+ lookup_count (0)
+ {}
~hb_closure_context_t () { flush (); }
void flush ()
{
+ hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
hb_set_union (glyphs, output);
hb_set_clear (output);
}
private:
hb_map_t *done_lookups;
+ unsigned int lookup_count;
};
+struct hb_closure_lookups_context_t :
+ hb_dispatch_context_t<hb_closure_lookups_context_t, hb_empty_t, 0>
+{
+ const char *get_name () { return "CLOSURE_LOOKUPS"; }
+ typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
+ template <typename T>
+ return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
+ static return_t default_return_value () { return hb_empty_t (); }
+ void recurse (unsigned lookup_index)
+ {
+ if (unlikely (nesting_level_left == 0 || !recurse_func))
+ return;
+
+ /* Return if new lookup was recursed to before. */
+ if (is_lookup_visited (lookup_index))
+ return;
+
+ set_lookup_visited (lookup_index);
+ nesting_level_left--;
+ recurse_func (this, lookup_index);
+ nesting_level_left++;
+ }
+
+ void set_lookup_visited (unsigned lookup_index)
+ { visited_lookups->add (lookup_index); }
+
+ void set_lookup_inactive (unsigned lookup_index)
+ { inactive_lookups->add (lookup_index); }
+
+ bool lookup_limit_exceeded ()
+ { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
+ bool is_lookup_visited (unsigned lookup_index)
+ {
+ if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+ return true;
+
+ return visited_lookups->has (lookup_index);
+ }
+
+ hb_face_t *face;
+ const hb_set_t *glyphs;
+ recurse_func_t recurse_func;
+ unsigned int nesting_level_left;
+ unsigned int debug_depth;
+
+ hb_closure_lookups_context_t (hb_face_t *face_,
+ const hb_set_t *glyphs_,
+ hb_set_t *visited_lookups_,
+ hb_set_t *inactive_lookups_,
+ unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+ face (face_),
+ glyphs (glyphs_),
+ recurse_func (nullptr),
+ nesting_level_left (nesting_level_left_),
+ debug_depth (0),
+ visited_lookups (visited_lookups_),
+ inactive_lookups (inactive_lookups_),
+ lookup_count (0) {}
+
+ void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+
+ private:
+ hb_set_t *visited_lookups;
+ hb_set_t *inactive_lookups;
+ unsigned int lookup_count;
+};
struct hb_would_apply_context_t :
hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
template <typename set_t>
-struct hb_add_coverage_context_t :
- hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
+struct hb_collect_coverage_context_t :
+ hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
{
const char *get_name () { return "GET_COVERAGE"; }
typedef const Coverage &return_t;
template <typename T>
return_t dispatch (const T &obj) { return obj.get_coverage (); }
- static return_t default_return_value () { return Null(Coverage); }
+ static return_t default_return_value () { return Null (Coverage); }
bool stop_sublookup_iteration (return_t r) const
{
- r.add_coverage (set);
+ r.collect_coverage (set);
return false;
}
- hb_add_coverage_context_t (set_t *set_) :
- set (set_),
- debug_depth (0) {}
+ hb_collect_coverage_context_t (set_t *set_) :
+ set (set_),
+ debug_depth (0) {}
set_t *set;
unsigned int debug_depth;
}
void reset (unsigned int start_index_,
- unsigned int num_items_)
+ unsigned int num_items_)
{
idx = start_index_;
num_items = num_items_;
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
}
- void reject () { num_items++; match_glyph_data--; }
+ void reject ()
+ {
+ num_items++;
+ if (match_glyph_data) match_glyph_data--;
+ }
matcher_t::may_skip_t
may_skip (const hb_glyph_info_t &info) const
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF->table
#else
- Null(GDEF)
+ Null (GDEF)
#endif
),
var_store (gdef.get_var_store ()),
return true;
}
- void _set_glyph_props (hb_codepoint_t glyph_index,
- unsigned int class_guess = 0,
- bool ligature = false,
- bool component = false) const
+ void _set_glyph_class (hb_codepoint_t glyph_index,
+ unsigned int class_guess = 0,
+ bool ligature = false,
+ bool component = false) const
{
- unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
- HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+ unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
+
+ props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
if (ligature)
{
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
+ props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
/* In the only place that the MULTIPLIED bit is used, Uniscribe
* seems to only care about the "last" transformation between
* Ligature and Multiple substitutions. Ie. if you ligate, expand,
* and ligate again, it forgives the multiplication and acts as
* if only ligation happened. As such, clear MULTIPLIED bit.
*/
- add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
if (component)
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+
if (likely (has_glyph_classes))
- _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
+ props = (props & ~HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK) | gdef.get_glyph_props (glyph_index);
else if (class_guess)
- _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
+ props = (props & ~HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK) | class_guess;
+
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
}
void replace_glyph (hb_codepoint_t glyph_index) const
{
- _set_glyph_props (glyph_index);
+ _set_glyph_class (glyph_index);
buffer->replace_glyph (glyph_index);
}
void replace_glyph_inplace (hb_codepoint_t glyph_index) const
{
- _set_glyph_props (glyph_index);
+ _set_glyph_class (glyph_index);
buffer->cur().codepoint = glyph_index;
}
void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess) const
{
- _set_glyph_props (glyph_index, class_guess, true);
+ _set_glyph_class (glyph_index, class_guess, true);
buffer->replace_glyph (glyph_index);
}
void output_glyph_for_component (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess) const
{
- _set_glyph_props (glyph_index, class_guess, false, true);
+ _set_glyph_class (glyph_index, class_guess, false, true);
buffer->output_glyph (glyph_index);
}
};
hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
{
template <typename Type>
- HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+ static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
{
const Type *typed_obj = (const Type *) obj;
return typed_obj->apply (c);
obj = &obj_;
apply_func = apply_func_;
digest.init ();
- obj_.get_coverage ().add_coverage (&digest);
+ obj_.get_coverage ().collect_coverage (&digest);
}
bool apply (OT::hb_ot_apply_context_t *c) const
return (data+coverage).intersects (glyphs);
}
-static inline bool intersects_array (const hb_set_t *glyphs,
- unsigned int count,
- const HBUINT16 values[],
- intersects_func_t intersects_func,
- const void *intersects_data)
+static inline bool array_is_subset_of (const hb_set_t *glyphs,
+ unsigned int count,
+ const HBUINT16 values[],
+ intersects_func_t intersects_func,
+ const void *intersects_data)
{
for (const HBUINT16 &_ : + hb_iter (values, count))
- if (intersects_func (glyphs, _, intersects_data)) return true;
- return false;
+ if (!intersects_func (glyphs, _, intersects_data)) return false;
+ return true;
}
static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- class_def.add_class (glyphs, value);
+ class_def.collect_class (glyphs, value);
}
static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
- (data+coverage).add_coverage (glyphs);
+ (data+coverage).collect_coverage (glyphs);
}
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
hb_set_t *glyphs,
buffer->idx++;
}
- if (!is_mark_ligature && last_lig_id) {
+ if (!is_mark_ligature && last_lig_id)
+ {
/* Re-adjust components for any marks following. */
- for (unsigned int i = buffer->idx; i < buffer->len; i++) {
- if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
- unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
- if (!this_comp)
- break;
- unsigned int new_lig_comp = components_so_far - last_num_components +
- hb_min (this_comp, last_num_components);
- _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
- } else
- break;
+ for (unsigned i = buffer->idx; i < buffer->len; ++i)
+ {
+ if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
+
+ unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+ if (!this_comp) break;
+
+ unsigned new_lig_comp = components_so_far - last_num_components +
+ hb_min (this_comp, last_num_components);
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
}
}
return_trace (true);
struct LookupRecord
{
+ LookupRecord* copy (hb_serialize_context_t *c,
+ const hb_map_t *lookup_map) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *out = c->embed (*this);
+ if (unlikely (!out)) return_trace (nullptr);
+
+ out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
+ return_trace (out);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
const HBUINT16 input[], /* Array of input values--start with second glyph */
ContextClosureLookupContext &lookup_context)
{
- return intersects_array (glyphs,
- inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data);
+ return array_is_subset_of (glyphs,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.intersects, lookup_context.intersects_data);
}
static inline void context_closure_lookup (hb_closure_context_t *c,
void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
context_closure_lookup (c,
lookup_context);
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+ recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
+ }
+
void collect_glyphs (hb_collect_glyphs_context_t *c,
ContextCollectGlyphsLookupContext &lookup_context) const
{
return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
}
+ bool serialize (hb_serialize_context_t *c,
+ const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
+ const hb_map_t *lookup_map) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *out = c->start_embed (this);
+ if (unlikely (!c->extend_min (out))) return_trace (false);
+
+ out->inputCount = inputCount;
+ out->lookupCount = lookupCount;
+
+ const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+ for (const auto org : input)
+ {
+ HBUINT16 d;
+ d = input_mapping->get (org);
+ c->copy (d);
+ }
+
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+ for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ c->copy (lookupRecord[i], lookup_map);
+
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const hb_map_t *lookup_map,
+ const hb_map_t *klass_map = nullptr) const
+ {
+ TRACE_SUBSET (this);
+
+ const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
+ if (!input.length) return_trace (false);
+
+ const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
+ if (!hb_all (input, mapping)) return_trace (false);
+ return_trace (serialize (c->serializer, mapping, lookup_map));
+ }
+
public:
bool sanitize (hb_sanitize_context_t *c) const
{
* glyph */
HBUINT16 lookupCount; /* Number of LookupRecords */
UnsizedArrayOf<HBUINT16>
- inputZ; /* Array of match inputs--start with
+ inputZ; /* Array of match inputs--start with
* second glyph */
/*UnsizedArrayOf<LookupRecord>
lookupRecordX;*/ /* Array of LookupRecords--in
void closure (hb_closure_context_t *c,
ContextClosureLookupContext &lookup_context) const
{
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
return
+ hb_iter (rule)
| hb_map (hb_add (this))
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
+ return
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
+ ;
+ }
+
void collect_glyphs (hb_collect_glyphs_context_t *c,
ContextCollectGlyphsLookupContext &lookup_context) const
{
;
}
+ bool subset (hb_subset_context_t *c,
+ const hb_map_t *lookup_map,
+ const hb_map_t *klass_map = nullptr) const
+ {
+ TRACE_SUBSET (this);
+
+ auto snap = c->serializer->snapshot ();
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ for (const OffsetTo<Rule>& _ : rule)
+ {
+ if (!_) continue;
+ auto *o = out->rule.serialize_append (c->serializer);
+ if (unlikely (!o)) continue;
+
+ auto o_snap = c->serializer->snapshot ();
+ if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
+ {
+ out->rule.pop ();
+ c->serializer->revert (o_snap);
+ }
+ }
+
+ bool ret = bool (out->rule);
+ if (!ret) c->serializer->revert (snap);
+
+ return_trace (ret);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ + hb_iter (ruleSet)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+ ;
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- (this+coverage).add_coverage (c->input);
+ (this+coverage).collect_coverage (c->input);
struct ContextCollectGlyphsLookupContext lookup_context = {
{collect_glyph},
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ + hb_zip (this+coverage, ruleSet)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+
+ out->coverage.serialize (c->serializer, out)
+ .serialize (c->serializer, new_coverage.iter ());
+ return_trace (bool (new_coverage));
}
bool sanitize (hb_sanitize_context_t *c) const
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ + hb_iter (ruleSet)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+ ;
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- (this+coverage).add_coverage (c->input);
+ (this+coverage).collect_coverage (c->input);
const ClassDef &class_def = this+classDef;
struct ContextCollectGlyphsLookupContext lookup_context = {
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+ if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
+ return_trace (false);
+
+ hb_map_t klass_map;
+ out->classDef.serialize_subset (c, classDef, this, &klass_map);
+
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ bool ret = true;
+ unsigned non_zero_index = 0, index = 0;
+ for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _ : + hb_enumerate (ruleSet)
+ | hb_filter (klass_map, hb_first))
+ {
+ auto *o = out->ruleSet.serialize_append (c->serializer);
+ if (unlikely (!o))
+ {
+ ret = false;
+ break;
+ }
+
+ if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+ non_zero_index = index;
+
+ index++;
+ }
+
+ if (!ret) return_trace (ret);
+
+ //prune empty trailing ruleSets
+ --index;
+ while (index > non_zero_index)
+ {
+ out->ruleSet.pop ();
+ index--;
+ }
+
+ return_trace (bool (out->ruleSet));
}
bool sanitize (hb_sanitize_context_t *c) const
lookup_context);
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
+ recurse_lookups (c, lookupCount, lookupRecord);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- (this+coverageZ[0]).add_coverage (c->input);
+ (this+coverageZ[0]).collect_coverage (c->input);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextCollectGlyphsLookupContext lookup_context = {
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ out->format = format;
+ out->glyphCount = glyphCount;
+ out->lookupCount = lookupCount;
+
+ const hb_array_t<const OffsetTo<Coverage>> coverages = coverageZ.as_array (glyphCount);
+
+ for (const OffsetTo<Coverage>& offset : coverages)
+ {
+ auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
+ if (unlikely (!o)) return_trace (false);
+ if (!o->serialize_subset (c, offset, this)) return_trace (false);
+ }
+
+ const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ c->serializer->copy (lookupRecord[i], lookup_map);
+
+ return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
const HBUINT16 lookahead[],
ChainContextClosureLookupContext &lookup_context)
{
- return intersects_array (glyphs,
- backtrackCount, backtrack,
- lookup_context.funcs.intersects, lookup_context.intersects_data[0])
- && intersects_array (glyphs,
- inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data[1])
- && intersects_array (glyphs,
- lookaheadCount, lookahead,
- lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+ return array_is_subset_of (glyphs,
+ backtrackCount, backtrack,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+ && array_is_subset_of (glyphs,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+ && array_is_subset_of (glyphs,
+ lookaheadCount, lookahead,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
}
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
void closure (hb_closure_context_t *c,
ChainContextClosureLookupContext &lookup_context) const
{
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
lookup_context);
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
+ const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+ const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ recurse_lookups (c, lookup.len, lookup.arrayZ);
+ }
+
void collect_glyphs (hb_collect_glyphs_context_t *c,
ChainContextCollectGlyphsLookupContext &lookup_context) const
{
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize_array (hb_serialize_context_t *c,
- HBUINT16 len,
- Iterator it) const
+ HBUINT16 len,
+ Iterator it) const
{
c->copy (len);
for (const auto g : it)
}
ChainRule* copy (hb_serialize_context_t *c,
+ const hb_map_t *lookup_map,
const hb_map_t *backtrack_map,
const hb_map_t *input_map = nullptr,
const hb_map_t *lookahead_map = nullptr) const
serialize_array (c, lookahead.len, + lookahead.iter ()
| hb_map (mapping));
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
- c->copy (lookup);
+ const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ HBUINT16 lookupCount;
+ lookupCount = lookupRecord.len;
+ if (!c->copy (lookupCount)) return_trace (nullptr);
+
+ for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
return_trace (out);
}
bool subset (hb_subset_context_t *c,
- const hb_map_t *backtrack_map = nullptr,
- const hb_map_t *input_map = nullptr,
- const hb_map_t *lookahead_map = nullptr) const
+ const hb_map_t *lookup_map,
+ const hb_map_t *backtrack_map = nullptr,
+ const hb_map_t *input_map = nullptr,
+ const hb_map_t *lookahead_map = nullptr) const
{
TRACE_SUBSET (this);
{
const hb_set_t &glyphset = *c->plan->glyphset ();
if (!hb_all (backtrack, glyphset) ||
- !hb_all (input, glyphset) ||
- !hb_all (lookahead, glyphset))
- return_trace (false);
+ !hb_all (input, glyphset) ||
+ !hb_all (lookahead, glyphset))
+ return_trace (false);
- copy (c->serializer, c->plan->glyph_map);
+ copy (c->serializer, lookup_map, c->plan->glyph_map);
}
else
{
if (!hb_all (backtrack, backtrack_map) ||
- !hb_all (input, input_map) ||
- !hb_all (lookahead, lookahead_map))
- return_trace (false);
+ !hb_all (input, input_map) ||
+ !hb_all (lookahead, lookahead_map))
+ return_trace (false);
- copy (c->serializer, backtrack_map, input_map, lookahead_map);
+ copy (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
}
return_trace (true);
}
void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
return
+ hb_iter (rule)
| hb_map (hb_add (this))
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ if (unlikely (c->lookup_limit_exceeded ())) return;
+
+ return
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
+ ;
+ }
+
void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
{
return
}
bool subset (hb_subset_context_t *c,
- const hb_map_t *backtrack_klass_map = nullptr,
- const hb_map_t *input_klass_map = nullptr,
- const hb_map_t *lookahead_klass_map = nullptr) const
+ const hb_map_t *lookup_map,
+ const hb_map_t *backtrack_klass_map = nullptr,
+ const hb_map_t *input_klass_map = nullptr,
+ const hb_map_t *lookahead_klass_map = nullptr) const
{
TRACE_SUBSET (this);
if (unlikely (!o)) continue;
auto o_snap = c->serializer->snapshot ();
- if (!o->serialize_subset (c, _, this, out,
- backtrack_klass_map,
- input_klass_map,
- lookahead_klass_map))
+ if (!o->serialize_subset (c, _, this,
+ lookup_map,
+ backtrack_klass_map,
+ input_klass_map,
+ lookahead_klass_map))
{
- out->rule.pop ();
- c->serializer->revert (o_snap);
+ out->rule.pop ();
+ c->serializer->revert (o_snap);
}
}
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ + hb_iter (ruleSet)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ ;
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- (this+coverage).add_coverage (c->input);
+ (this+coverage).collect_coverage (c->input);
struct ChainContextCollectGlyphsLookupContext lookup_context = {
{collect_glyph},
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, ruleSet)
| hb_filter (glyphset, hb_first)
- | hb_filter (subset_offset_array (c, out->ruleSet, this, out), hb_second)
+ | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ + hb_iter (ruleSet)
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ ;
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- (this+coverage).add_coverage (c->input);
+ (this+coverage).collect_coverage (c->input);
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
- out->coverage.serialize_subset (c, coverage, this, out);
+ out->coverage.serialize_subset (c, coverage, this);
hb_map_t backtrack_klass_map;
- out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, out, &backtrack_klass_map);
+ out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
// subset inputClassDef based on glyphs survived in Coverage subsetting
hb_map_t input_klass_map;
- out->inputClassDef.serialize_subset (c, inputClassDef, this, out, &input_klass_map);
+ out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
hb_map_t lookahead_klass_map;
- out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, out, &lookahead_klass_map);
+ out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
- hb_vector_t<unsigned> rulesets;
+ unsigned non_zero_index = 0, index = 0;
bool ret = true;
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
| hb_filter (input_klass_map, hb_first)
| hb_map (hb_second))
auto *o = out->ruleSet.serialize_append (c->serializer);
if (unlikely (!o))
{
- ret = false;
- break;
- }
- if (!o->serialize_subset (c, _, this, out,
- &backtrack_klass_map,
- &input_klass_map,
- &lookahead_klass_map))
- {
- rulesets.push (0);
+ ret = false;
+ break;
}
- else rulesets.push (1);
+ if (o->serialize_subset (c, _, this,
+ lookup_map,
+ &backtrack_klass_map,
+ &input_klass_map,
+ &lookahead_klass_map))
+ non_zero_index = index;
+
+ index++;
}
if (!ret) return_trace (ret);
//prune empty trailing ruleSets
- unsigned count = rulesets.length;
- while (count > 0 && rulesets[count-1] == 0)
+ --index;
+ while (index > non_zero_index)
{
out->ruleSet.pop ();
- count--;
+ index--;
}
return_trace (bool (out->ruleSet));
lookup_context);
}
+ void closure_lookups (hb_closure_lookups_context_t *c) const
+ {
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ recurse_lookups (c, lookup.len, lookup.arrayZ);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
- (this+input[0]).add_coverage (c->input);
+ (this+input[0]).collect_coverage (c->input);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize_coverage_offsets (hb_subset_context_t *c,
- Iterator it,
- const void* src_base,
- const void* dst_base) const
+ bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+ it
- | hb_apply (subset_offset_array (c, *out, src_base, dst_base))
+ | hb_apply (subset_offset_array (c, *out, base))
;
return_trace (out->len);
if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
- if (!serialize_coverage_offsets (c, backtrack.iter (), this, out))
+ if (!serialize_coverage_offsets (c, backtrack.iter (), this))
return_trace (false);
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
- if (!serialize_coverage_offsets (c, input.iter (), this, out))
+ if (!serialize_coverage_offsets (c, input.iter (), this))
return_trace (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- if (!serialize_coverage_offsets (c, lookahead.iter (), this, out))
+ if (!serialize_coverage_offsets (c, lookahead.iter (), this))
return_trace (false);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
- return_trace (c->serializer->copy (lookup));
+ const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ HBUINT16 lookupCount;
+ lookupCount = lookupRecord.len;
+ if (!c->serializer->copy (lookupCount)) return_trace (false);
+
+ const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ if (!c->serializer->copy (lookupRecord[i], lookup_map)) return_trace (false);
+
+ return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
template <typename X>
const X& get_subtable () const
- { return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
+ { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
}
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ { dispatch (c); }
+
/* This is called from may_dispatch() above with hb_sanitize_context_t. */
bool sanitize (hb_sanitize_context_t *c) const
{
{
switch (u.format) {
case 1: return u.format1.template get_subtable<typename T::SubTable> ();
- default:return Null(typename T::SubTable);
+ default:return Null (typename T::SubTable);
}
}
void init (const TLookup &lookup)
{
digest.init ();
- lookup.add_coverage (&digest);
+ lookup.collect_coverage (&digest);
subtables.init ();
OT::hb_get_subtables_context_t c_get_subtables (subtables);
bool find_variations_index (const int *coords, unsigned int num_coords,
unsigned int *index) const
{
-#ifdef HB_NOVAR
+#ifdef HB_NO_VAR
+ *index = FeatureVariations::NOT_FOUND_INDEX;
return false;
#endif
- return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+ return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
.find_index (coords, num_coords, index);
}
const Feature& get_feature_variation (unsigned int feature_index,
return get_feature (feature_index);
}
+ void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+ hb_set_t *lookup_indexes /* OUT */) const
+ {
+#ifndef HB_NO_VAR
+ if (version.to_int () >= 0x00010001u)
+ (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+#endif
+ }
+
template <typename TLookup>
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_layout_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->embed (*this);
+ auto *out = c->subset_context->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
- out->scriptList.serialize_subset (c, scriptList, this, out);
- out->featureList.serialize_subset (c, featureList, this, out);
+ typedef LookupOffsetList<TLookup> TLookupList;
+ reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
+ .serialize_subset (c->subset_context,
+ reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
+ this,
+ c);
- typedef OffsetListOf<TLookup> TLookupList;
- /* TODO Use intersects() to count how many subtables survive? */
- CastR<OffsetTo<TLookupList>> (out->lookupList)
- .serialize_subset (c,
- CastR<OffsetTo<TLookupList>> (lookupList),
- this,
- out);
+ reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
+ .serialize_subset (c->subset_context,
+ reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
+ this,
+ c);
+
+ out->scriptList.serialize_subset (c->subset_context,
+ scriptList,
+ this,
+ c);
#ifndef HB_NO_VAR
if (version.to_int () >= 0x00010001u)
- out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
+ {
+ bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
+ if (!ret)
+ {
+ out->version.major = 1;
+ out->version.minor = 0;
+ }
+ }
#endif
return_trace (true);
}
+ void closure_features (const hb_map_t *lookup_indexes, /* IN */
+ hb_set_t *feature_indexes /* OUT */) const
+ {
+ unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
+ for (unsigned i = 0; i < feature_count; i++)
+ {
+ const Feature& f = get_feature (i);
+ if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
+ feature_indexes->add (i);
+ }
+#ifndef HB_NO_VAR
+ if (version.to_int () >= 0x00010001u)
+ (this+featureVars).closure_features (lookup_indexes, feature_indexes);
+#endif
+ }
+
unsigned int get_size () const
{
return min_size +
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
- CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this))))
+ reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
return_trace (false);
#ifndef HB_NO_VAR
{
void init (hb_face_t *face)
{
- this->table = hb_sanitize_context_t().reference_table<T> (face);
+ this->table = hb_sanitize_context_t ().reference_table<T> (face);
if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
{
hb_blob_destroy (this->table.get_blob ());
FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000u */
OffsetTo<ScriptList>
- scriptList; /* ScriptList table */
+ scriptList; /* ScriptList table */
OffsetTo<FeatureList>
- featureList; /* FeatureList table */
+ featureList; /* FeatureList table */
OffsetTo<LookupList>
- lookupList; /* LookupList table */
+ lookupList; /* LookupList table */
LOffsetTo<FeatureVariations>
featureVars; /* Offset to Feature Variations
table--from beginning of table