[subset] subset lookup/feature/script lists for GSUB/GPOS
This commit is contained in:
parent
93376a6436
commit
e565d1f9bc
|
@ -82,6 +82,44 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
|
|||
hb_sorted_vector_t<unsigned> klasses,
|
||||
hb_map_t *klass_map /*INOUT*/);
|
||||
|
||||
struct hb_subset_layout_context_t :
|
||||
hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET>
|
||||
{
|
||||
const char *get_name () { return "SUBSET_LAYOUT"; }
|
||||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
|
||||
bool visitScript ()
|
||||
{
|
||||
return script_count++ < HB_MAX_SCRIPTS;
|
||||
}
|
||||
|
||||
bool visitLangSys ()
|
||||
{
|
||||
return langsys_count++ < HB_MAX_LANGSYS;
|
||||
}
|
||||
|
||||
hb_subset_context_t *subset_context;
|
||||
const hb_tag_t table_tag;
|
||||
const hb_map_t *lookup_index_map;
|
||||
const hb_map_t *feature_index_map;
|
||||
unsigned debug_depth;
|
||||
|
||||
hb_subset_layout_context_t (hb_subset_context_t *c_,
|
||||
hb_tag_t tag_,
|
||||
hb_map_t *lookup_map_,
|
||||
hb_map_t *feature_map_) :
|
||||
subset_context (c_),
|
||||
table_tag (tag_),
|
||||
lookup_index_map (lookup_map_),
|
||||
feature_index_map (feature_map_),
|
||||
debug_depth (0),
|
||||
script_count (0),
|
||||
langsys_count (0) {}
|
||||
|
||||
private:
|
||||
unsigned script_count;
|
||||
unsigned langsys_count;
|
||||
};
|
||||
|
||||
template<typename OutputArray>
|
||||
struct subset_offset_array_t
|
||||
|
@ -137,6 +175,53 @@ struct
|
|||
}
|
||||
HB_FUNCOBJ (subset_offset_array);
|
||||
|
||||
template<typename OutputArray>
|
||||
struct subset_record_array_t
|
||||
{
|
||||
subset_record_array_t
|
||||
(hb_subset_layout_context_t *c,
|
||||
OutputArray* out,
|
||||
const void *src_base,
|
||||
const void *dest_base)
|
||||
: _subset_layout_context(c), _out (out), _src_base (src_base), _dest_base (dest_base) {}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
operator ()
|
||||
(T&& record)
|
||||
{
|
||||
auto snap = _subset_layout_context->subset_context->serializer->snapshot ();
|
||||
bool ret = record.subset (_subset_layout_context, _src_base, _dest_base);
|
||||
if (!ret) _subset_layout_context->subset_context->serializer->revert (snap);
|
||||
else _out->len++;
|
||||
}
|
||||
|
||||
private:
|
||||
hb_subset_layout_context_t *_subset_layout_context;
|
||||
OutputArray *_out;
|
||||
const void *_src_base;
|
||||
const void *_dest_base;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper to subset a RecordList/record array. Subsets each Record in the array and
|
||||
* discards the record if the subset operation returns false.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
template<typename OutputArray>
|
||||
subset_record_array_t<OutputArray>
|
||||
operator ()
|
||||
(hb_subset_layout_context_t *c,
|
||||
OutputArray* out,
|
||||
const void *src_base,
|
||||
const void *dest_base) const
|
||||
{
|
||||
return subset_record_array_t<OutputArray> (c, out, src_base, dest_base);
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (subset_record_array);
|
||||
|
||||
/*
|
||||
*
|
||||
* OpenType Layout Common Table Formats
|
||||
|
@ -153,31 +238,22 @@ struct Record_sanitize_closure_t {
|
|||
const void *list_base;
|
||||
};
|
||||
|
||||
struct RecordList_subset_context_t {
|
||||
|
||||
RecordList_subset_context_t() : script_count (0), langsys_count (0)
|
||||
{}
|
||||
|
||||
bool visitScript ()
|
||||
{
|
||||
return script_count++ < HB_MAX_SCRIPTS;
|
||||
}
|
||||
|
||||
bool visitLangSys ()
|
||||
{
|
||||
return langsys_count++ < HB_MAX_LANGSYS;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int script_count;
|
||||
unsigned int langsys_count;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct Record
|
||||
{
|
||||
int cmp (hb_tag_t a) const { return tag.cmp (a); }
|
||||
|
||||
bool subset (hb_subset_layout_context_t *c,
|
||||
const void *src_base,
|
||||
const void *dst_base) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->subset_context->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
bool ret = out->offset.serialize_subset (c->subset_context, offset, src_base, dst_base, c, &tag);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -226,29 +302,16 @@ struct RecordListOf : RecordArrayOf<Type>
|
|||
const Type& operator [] (unsigned int i) const
|
||||
{ return this+this->get_offset (i); }
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
RecordList_subset_context_t record_list_context;
|
||||
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
auto *record = out->serialize_append (c->serializer);
|
||||
if (unlikely (!record)) return false;
|
||||
auto snap = c->serializer->snapshot ();
|
||||
if (record->offset.serialize_subset (c, this->get_offset (i), this, out, &record_list_context))
|
||||
{
|
||||
record->tag = this->get_tag(i);
|
||||
continue;
|
||||
}
|
||||
out->pop ();
|
||||
c->serializer->revert (snap);
|
||||
}
|
||||
|
||||
+ this->iter ()
|
||||
| hb_apply (subset_record_array (l, out, this, out))
|
||||
;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
|
@ -259,6 +322,26 @@ struct RecordListOf : RecordArrayOf<Type>
|
|||
}
|
||||
};
|
||||
|
||||
struct Feature;
|
||||
|
||||
struct RecordListOfFeature : RecordListOf<Feature>
|
||||
{
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
unsigned count = this->len;
|
||||
+ hb_zip (*this, hb_range (count))
|
||||
| hb_filter (l->feature_index_map, hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_apply (subset_record_array (l, out, this, out))
|
||||
;
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
struct RangeRecord
|
||||
{
|
||||
|
@ -292,6 +375,23 @@ struct IndexArray : ArrayOf<Index>
|
|||
bool intersects (const hb_map_t *indexes) const
|
||||
{ return hb_any (*this, indexes); }
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
void serialize (hb_serialize_context_t *c,
|
||||
Iterator it)
|
||||
{
|
||||
if (!it.len ()) return;
|
||||
if (unlikely (!c->extend_min ((*this)))) return;
|
||||
|
||||
this->len = it.len ();
|
||||
for (const auto _ : it)
|
||||
{
|
||||
Index i;
|
||||
i = _;
|
||||
c->copy (i);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int get_indexes (unsigned int start_offset,
|
||||
unsigned int *_count /* IN/OUT */,
|
||||
unsigned int *_indexes /* OUT */) const
|
||||
|
@ -312,10 +412,6 @@ struct IndexArray : ArrayOf<Index>
|
|||
};
|
||||
|
||||
|
||||
struct Script;
|
||||
struct LangSys;
|
||||
struct Feature;
|
||||
|
||||
struct LangSys
|
||||
{
|
||||
unsigned int get_feature_count () const
|
||||
|
@ -343,6 +439,39 @@ struct LangSys
|
|||
return_trace (c->embed (*this));
|
||||
}
|
||||
|
||||
bool operator == (const LangSys& o) const
|
||||
{
|
||||
if (featureIndex.len != o.featureIndex.len ||
|
||||
reqFeatureIndex != o.reqFeatureIndex)
|
||||
return false;
|
||||
|
||||
for (const auto _ : + hb_zip (featureIndex, o.featureIndex))
|
||||
if (_.first != _.second) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l,
|
||||
const Tag *tag = nullptr) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
|
||||
|
||||
auto it =
|
||||
+ hb_iter (featureIndex)
|
||||
| hb_filter (l->feature_index_map)
|
||||
| hb_map (l->feature_index_map)
|
||||
;
|
||||
|
||||
bool ret = bool (it);
|
||||
out->featureIndex.serialize (c->serializer, it);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
const Record_sanitize_closure_t * = nullptr) const
|
||||
{
|
||||
|
@ -382,34 +511,46 @@ struct Script
|
|||
bool has_default_lang_sys () const { return defaultLangSys != 0; }
|
||||
const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
|
||||
|
||||
bool subset (hb_subset_context_t *c, RecordList_subset_context_t *record_list_context) const
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l,
|
||||
const Tag *tag) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (!record_list_context->visitScript ()) return_trace (false);
|
||||
if (!l->visitScript ()) return_trace (false);
|
||||
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->defaultLangSys.serialize_copy (c->serializer, defaultLangSys, this, out);
|
||||
|
||||
for (const auto &src: langSys)
|
||||
bool defaultLang = false;
|
||||
if (has_default_lang_sys ())
|
||||
{
|
||||
if (!record_list_context->visitLangSys ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto snap = c->serializer->snapshot ();
|
||||
auto *lang_sys = c->serializer->embed (src);
|
||||
|
||||
if (likely(lang_sys)
|
||||
&& lang_sys->offset.serialize_copy (c->serializer, src.offset, this, out))
|
||||
c->serializer->push ();
|
||||
const LangSys& ls = this+defaultLangSys;
|
||||
bool ret = ls.subset (c, l);
|
||||
if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
|
||||
{
|
||||
out->langSys.len++;
|
||||
continue;
|
||||
c->serializer->pop_discard ();
|
||||
out->defaultLangSys = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack (), out);
|
||||
defaultLang = true;
|
||||
}
|
||||
c->serializer->revert (snap);
|
||||
}
|
||||
return_trace (true);
|
||||
|
||||
+ langSys.iter ()
|
||||
| hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
|
||||
| hb_filter ([&] (const Record<LangSys>& record)
|
||||
{
|
||||
const LangSys& d = this+defaultLangSys;
|
||||
const LangSys& l = this+record.offset;
|
||||
return !(l == d);
|
||||
})
|
||||
| hb_apply (subset_record_array (l, &(out->langSys), this, out))
|
||||
;
|
||||
|
||||
return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
|
@ -688,13 +829,24 @@ struct Feature
|
|||
bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
|
||||
{ return lookupIndex.intersects (lookup_indexes); }
|
||||
|
||||
bool subset (hb_subset_context_t *c, RecordList_subset_context_t *r) const
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l,
|
||||
const Tag *tag = nullptr) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->featureParams = 0; /* TODO(subset) FeatureParams. */
|
||||
return_trace (true);
|
||||
|
||||
auto it =
|
||||
+ hb_iter (lookupIndex)
|
||||
| hb_filter (l->lookup_index_map)
|
||||
| hb_map (l->lookup_index_map)
|
||||
;
|
||||
|
||||
out->lookupIndex.serialize (c->serializer, it);
|
||||
return_trace (bool (it) || (tag && *tag == HB_TAG ('p', 'r', 'e', 'f')));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
|
@ -918,6 +1070,32 @@ struct Lookup
|
|||
|
||||
typedef OffsetListOf<Lookup> LookupList;
|
||||
|
||||
template <typename TLookup>
|
||||
struct LookupOffsetList : OffsetListOf<TLookup>
|
||||
{
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
unsigned count = this->len;
|
||||
+ hb_zip (*this, hb_range (count))
|
||||
| hb_filter (l->lookup_index_map, hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_apply (subset_offset_array (c, *out, this, out))
|
||||
;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (OffsetListOf<TLookup>::sanitize (c, this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Coverage Table
|
||||
|
@ -2227,6 +2405,14 @@ struct ConditionFormat1
|
|||
{
|
||||
friend struct Condition;
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
private:
|
||||
bool evaluate (const int *coords, unsigned int coord_len) const
|
||||
{
|
||||
|
@ -2259,6 +2445,17 @@ struct Condition
|
|||
}
|
||||
}
|
||||
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2289,6 +2486,18 @@ struct ConditionSet
|
|||
return true;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
+ conditions.iter ()
|
||||
| hb_apply (subset_offset_array (c, out->conditions, this, out))
|
||||
;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2318,6 +2527,19 @@ struct FeatureTableSubstitutionRecord
|
|||
feature_indexes->add (featureIndex);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_layout_context_t *c,
|
||||
const void *src_base,
|
||||
const void *dst_base) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->subset_context->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->featureIndex = c->feature_index_map->get (featureIndex);
|
||||
bool ret = out->feature.serialize_subset (c->subset_context, feature, src_base, dst_base, c);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2364,6 +2586,22 @@ struct FeatureTableSubstitution
|
|||
record.closure_features (this, lookup_indexes, feature_indexes);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->version.major = version.major;
|
||||
out->version.minor = version.minor;
|
||||
|
||||
+ substitutions.iter ()
|
||||
| hb_apply (subset_record_array (l, &(out->substitutions), this, out))
|
||||
;
|
||||
return_trace (bool (out->substitutions));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2398,6 +2636,20 @@ struct FeatureVariationRecord
|
|||
(base+substitutions).closure_features (lookup_indexes, feature_indexes);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_layout_context_t *c,
|
||||
const void *src_base,
|
||||
const void *dst_base) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->subset_context->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->conditions.serialize_subset (c->subset_context, conditions, src_base, dst_base);
|
||||
|
||||
bool ret = out->substitutions.serialize_subset (c->subset_context, substitutions, src_base, dst_base, c);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2462,6 +2714,22 @@ struct FeatureVariations
|
|||
record.closure_features (this, lookup_indexes, feature_indexes);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
hb_subset_layout_context_t *l) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->version.major = version.major;
|
||||
out->version.minor = version.minor;
|
||||
|
||||
+ varRecords.iter ()
|
||||
| hb_apply (subset_record_array (l, &(out->varRecords), this, out))
|
||||
;
|
||||
return_trace (bool (out->varRecords));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
|
|
@ -1960,7 +1960,10 @@ struct GPOS : GSUBGPOS
|
|||
static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{ return GSUBGPOS::subset<PosLookup> (c); }
|
||||
{
|
||||
hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_features);
|
||||
return GSUBGPOS::subset<PosLookup> (&l);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return GSUBGPOS::sanitize<PosLookup> (c); }
|
||||
|
|
|
@ -1533,7 +1533,10 @@ struct GSUB : GSUBGPOS
|
|||
{ return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{ return GSUBGPOS::subset<SubstLookup> (c); }
|
||||
{
|
||||
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_features);
|
||||
return GSUBGPOS::subset<SubstLookup> (&l);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
|
||||
|
|
|
@ -3058,26 +3058,43 @@ struct GSUBGPOS
|
|||
}
|
||||
|
||||
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 OffsetListOf<TLookup> TLookupList;
|
||||
/* TODO Use intersects() to count how many subtables survive? */
|
||||
typedef LookupOffsetList<TLookup> TLookupList;
|
||||
reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
|
||||
.serialize_subset (c,
|
||||
reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
|
||||
this,
|
||||
out);
|
||||
.serialize_subset (c->subset_context,
|
||||
reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
|
||||
this,
|
||||
out,
|
||||
c);
|
||||
|
||||
reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
|
||||
.serialize_subset (c->subset_context,
|
||||
reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
|
||||
this,
|
||||
out,
|
||||
c);
|
||||
|
||||
out->scriptList.serialize_subset (c->subset_context,
|
||||
scriptList,
|
||||
this,
|
||||
out,
|
||||
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, out, c);
|
||||
if (!ret)
|
||||
{
|
||||
out->version.major = 1;
|
||||
out->version.major = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return_trace (true);
|
||||
|
|
|
@ -77,7 +77,14 @@ test_face (hb_face_t *face,
|
|||
hb_set_t *lookup_indexes = hb_set_create ();
|
||||
hb_set_add (lookup_indexes, 0);
|
||||
hb_ot_layout_closure_lookups (face, HB_OT_TAG_GSUB, set, lookup_indexes);
|
||||
|
||||
hb_map_t *lookup_mapping = hb_map_create ();
|
||||
hb_map_set (lookup_mapping, 0, 0);
|
||||
hb_set_t *feature_indices = hb_set_create ();
|
||||
hb_ot_layout_closure_features (face, HB_OT_TAG_GSUB, lookup_mapping, feature_indices);
|
||||
hb_set_destroy (lookup_indexes);
|
||||
hb_set_destroy (feature_indices);
|
||||
hb_map_destroy (lookup_mapping);
|
||||
|
||||
hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL);
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -8,4 +8,5 @@ SUBSETS:
|
|||
AC
|
||||
CF
|
||||
AF
|
||||
BD
|
||||
*
|
||||
|
|
|
@ -9,4 +9,5 @@ keep-layout-retain-gids.txt
|
|||
SUBSETS:
|
||||
!#
|
||||
!#%
|
||||
ABC
|
||||
*
|
||||
|
|
|
@ -9,4 +9,5 @@ SUBSETS:
|
|||
()
|
||||
(+
|
||||
)+
|
||||
ABC
|
||||
*
|
||||
|
|
|
@ -9,4 +9,5 @@ keep-layout-retain-gids.txt
|
|||
|
||||
SUBSETS:
|
||||
0123
|
||||
ABC
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue