// TODO(garretrieger): cleanup these after migration. using OT::Layout::Common::Coverage; using OT::Layout::Common::RangeRecord; using OT::Layout::SmallTypes; using OT::Layout::MediumTypes;
/* * Helper to subset an array of offsets. Subsets the thing pointed to by each offset * and discards the offset in the array if the subset operation results in an empty * thing.
*/ struct
{ template<typename OutputArray>
subset_offset_array_t<OutputArray> operator () (hb_subset_context_t *subset_context, OutputArray& out, constvoid *base) const
{ return subset_offset_array_t<OutputArray> (subset_context, out, base); }
/* Variant with one extra argument passed to serialize_subset */ template<typename OutputArray, typename Arg>
subset_offset_array_arg_t<OutputArray, Arg> operator () (hb_subset_context_t *subset_context, OutputArray& out, constvoid *base, Arg &&arg) const
{ return subset_offset_array_arg_t<OutputArray, Arg> (subset_context, out, base, arg); }
}
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_, constvoid *base_) : subset_layout_context (c_),
out (out_), base (base_) {}
template <typename T> void operator () (T&& record)
{ auto snap = subset_layout_context->subset_context->serializer->snapshot (); bool ret = record.subset (subset_layout_context, base); if (!ret) subset_layout_context->subset_context->serializer->revert (snap); else out->len++;
}
/* * 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, constvoid *base) const
{ return subset_record_array_t<OutputArray> (c, out, base); }
/* Variant with one extra argument passed to subset */ template<typename OutputArray, typename Arg>
subset_record_array_arg_t<OutputArray, Arg> operator () (hb_subset_layout_context_t *c, OutputArray* out, constvoid *base, Arg &&arg) const
{ return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
}
HB_FUNCOBJ (subset_record_array);
template<typename OutputArray> struct serialize_math_record_array_t
{
serialize_math_record_array_t (hb_serialize_context_t *serialize_context_,
OutputArray& out_, constvoid *base_) : serialize_context (serialize_context_),
out (out_), base (base_) {}
/* This subtable has some "history", if you will. Some earlier versions of * Adobe tools calculated the offset of the FeatureParams subtable from the * beginning of the FeatureList table! Now, that is dealt with in the * Feature implementation. But we still need to be able to tell junk from * real data. Note: We don't check that the nameID actually exists. * * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : * * Yes, it is correct that a new version of the AFDKO (version 2.0) will be * coming out soon, and that the makeotf program will build a font with a * 'size' feature that is correct by the specification. * * The specification for this feature tag is in the "OpenType Layout Tag * Registry". You can see a copy of this at: * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size * * Here is one set of rules to determine if the 'size' feature is built * correctly, or as by the older versions of MakeOTF. You may be able to do * better. * * Assume that the offset to the size feature is according to specification, * and make the following value checks. If it fails, assume the size * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. * If this fails, reject the 'size' feature. The older makeOTF's calculated the * offset from the beginning of the FeatureList table, rather than from the * beginning of the 'size' Feature table. * * If "design size" == 0: * fails check * * Else if ("subfamily identifier" == 0 and * "range start" == 0 and * "range end" == 0 and * "range start" == 0 and * "menu name ID" == 0) * passes check: this is the format used when there is a design size * specified, but there is no recommended size range. * * Else if ("design size" < "range start" or * "design size" > "range end" or * "range end" <= "range start" or * "menu name ID" < 256 or * "menu name ID" > 32767 or * menu name ID is not a name ID which is actually in the name table) * fails test * Else * passes test.
*/
HBUINT16 designSize; /* Represents the design size in 720/inch * units (decipoints). The design size entry * must be non-zero. When there is a design * size but no recommended size range, the
* rest of the array will consist of zeros. */
HBUINT16 subfamilyID; /* Has no independent meaning, but serves * as an identifier that associates fonts * in a subfamily. All fonts which share a * Preferred or Font Family name and which * differ only by size range shall have the * same subfamily value, and no fonts which * differ in weight or style shall have the * same subfamily value. If this value is * zero, the remaining fields in the array
* will be ignored. */
NameID subfamilyNameID;/* If the preceding value is non-zero, this * value must be set in the range 256 - 32767 * (inclusive). It records the value of a * field in the name table, which must * contain English-language strings encoded * in Windows Unicode and Macintosh Roman, * and may contain additional strings * localized to other scripts and languages. * Each of these strings is the name an * application should use, in combination * with the family name, to represent the * subfamily in a menu. Applications will * choose the appropriate version based on
* their selection criteria. */
HBUINT16 rangeStart; /* Large end of the recommended usage range * (inclusive), stored in 720/inch units
* (decipoints). */
HBUINT16 rangeEnd; /* Small end of the recommended usage range (exclusive), stored in 720/inch units
* (decipoints). */ public:
DEFINE_SIZE_STATIC (10);
};
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */ struct FeatureParamsStylisticSet
{ bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this); /* Right now minorVersion is at zero. Which means, any table supports
* the uiNameID field. */
return_trace (c->check_struct (this));
}
HBUINT16 version; /* (set to 0): This corresponds to a “minor” * version number. Additional data may be * added to the end of this Feature Parameters
* table in the future. */
NameID uiNameID; /* The 'name' table name ID that specifies a * string (or strings, for multiple languages) * for a user-interface label for this * feature. The values of uiLabelNameId and * sampleTextNameId are expected to be in the * font-specific name ID range (256-32767), * though that is not a requirement in this * Feature Parameters specification. The * user-interface label for the feature can * be provided in multiple languages. An * English string should be included as a * fallback. The string should be kept to a * minimal length to fit comfortably with
* different application interfaces. */ public:
DEFINE_SIZE_STATIC (4);
};
HBUINT16 format; /* Format number is set to 0. */
NameID featUILableNameID; /* The ‘name’ table name ID that * specifies a string (or strings, * for multiple languages) for a * user-interface label for this
* feature. (May be NULL.) */
NameID featUITooltipTextNameID;/* The ‘name’ table name ID that * specifies a string (or strings, * for multiple languages) that an * application can use for tooltip * text for this feature. (May be
* nullptr.) */
NameID sampleTextNameID; /* The ‘name’ table name ID that * specifies sample text that * illustrates the effect of this
* feature. (May be NULL.) */
HBUINT16 numNamedParameters; /* Number of named parameters. (May
* be zero.) */
NameID firstParamUILabelNameID;/* The first ‘name’ table name ID * used to specify strings for * user-interface labels for the * feature parameters. (Must be zero
* if numParameters is zero.) */
Array16Of<HBUINT24>
characters; /* Array of the Unicode Scalar Value * of the characters for which this * feature provides glyph variants.
* (May be zero.) */ public:
DEFINE_SIZE_ARRAY (14, characters);
};
auto it =
+ hb_iter (lookupIndex)
| hb_filter (l->lookup_index_map)
| hb_map (l->lookup_index_map)
;
out->lookupIndex.serialize (c->serializer, l, it); // The decision to keep or drop this feature is already made before we get here // so always retain it.
return_trace (true);
}
/* Some earlier versions of Adobe tools calculated the offset of the * FeatureParams subtable from the beginning of the FeatureList table! * * If sanitizing "failed" for the FeatureParams subtable, try it with the * alternative location. We would know sanitize "failed" if old value * of the offset was non-zero, but it's zeroed now. * * Only do this for the 'size' feature, since at the time of the faulty * Adobe tools, only the 'size' feature had FeatureParams defined.
*/
if (likely (featureParams.is_null ()))
return_trace (true);
Offset16To<FeatureParams> new_offset; /* Check that it would not overflow. */
new_offset = new_offset_int; if (new_offset == new_offset_int &&
c->try_set (&featureParams, new_offset_int) &&
!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
return_trace (false);
}
return_trace (true);
}
Offset16To<FeatureParams>
featureParams; /* Offset to Feature Parameters table (if one * has been defined for the feature), relative * to the beginning of the Feature Table; = Null
* if not required */
IndexArray lookupIndex; /* Array of LookupList indices */ public:
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
};
template <typename Type> struct Record
{ int cmp (hb_tag_t a) const { return tag.cmp (a); }
Tag tag; /* 4-byte Tag identifier */
Offset16To<Type>
offset; /* Offset from beginning of object holding
* the Record */ public:
DEFINE_SIZE_STATIC (6);
};
Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
* reordering table) */
HBUINT16 reqFeatureIndex;/* Index of a feature required for this * language system--if no required features
* = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */ public:
DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
};
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
void prune_langsys (hb_prune_langsys_context_t *c, unsigned script_index) const
{ if (!has_default_lang_sys () && !get_lang_sys_count ()) return; if (!c->visitScript ()) return;
if (!c->script_langsys_map->has (script_index))
{ if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()}))) return;
}
if (has_default_lang_sys ())
{ //only collect features from non-redundant langsys const LangSys& d = get_default_lang_sys (); if (c->visitLangsys (d.get_feature_count ())) {
d.collect_features (c);
}
for (auto _ : + hb_enumerate (langSys))
{ const LangSys& l = this+_.second.offset; if (!c->visitLangsys (l.get_feature_count ())) continue; if (l.compare (d, c->duplicate_feature_map)) continue;
/* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and * higher 16-bit is mark-filtering-set if the lookup uses one.
* Not to be confused with glyph_props which is very similar. */
uint32_t get_props () const
{ unsignedint flag = lookupFlag; if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
{ const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
flag += (markFilteringSet << 16);
} return flag;
}
// Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup // indices being consistent with those computed during planning. So if an empty lookup is // discarded during the subset phase it will invalidate all subsequent lookup indices. // Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning // phase, but it can happen in rare cases such as when during closure subtable is considered // degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
return_trace (true);
}
/* The spec says all subtables of an Extension lookup should * have the same type, which shall not be the Extension type * itself (but we already checked for that). * This is specially important if one has a reverse type! * * We only do this if sanitizer edit_count is zero. Otherwise, * some of the subtables might have become insane after they * were sanity-checked by the edits of subsequent subtables. * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
*/ unsignedint type = get_subtable<TSubTable> (0).u.extension.get_type (); for (unsignedint i = 1; i < subtables; i++) if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
return_trace (false);
}
return_trace (true);
}
protected:
HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
HBUINT16 lookupFlag; /* Lookup qualifiers */
Array16Of<Offset16>
subTable; /* Array of SubTables */ /*HBUINT16 markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
* structure. This field is only present if bit
* UseMarkFilteringSet of lookup flags is set. */ public:
DEFINE_SIZE_ARRAY (6, subTable);
};
template <typename Types> using LookupList = List16OfOffsetTo<Lookup, typename Types::HBUINT>;
/* any glyph not assigned a class value falls into Class zero (0),
* if any glyph assigned to class 0, remapping must start with 0->0*/ if (!use_class_zero)
klass_map->set (0, 0);
for (unsigned i = 0; i < glyph_and_klass.length; i++)
{
hb_codepoint_t klass = glyph_and_klass[i].second;
glyph_and_klass[i].second = klass_map->get (klass);
}
template <typename set_t> bool collect_coverage (set_t *glyphs) const
{ for (auto &range : rangeRecord) if (range.value) if (unlikely (!range.collect_coverage (glyphs))) returnfalse; returntrue;
}
template <typename set_t> bool collect_class (set_t *glyphs, unsignedint klass) const
{ for (auto &range : rangeRecord)
{ if (range.value == klass) if (unlikely (!range.collect_coverage (glyphs))) returnfalse;
} returntrue;
}
bool intersects (const hb_set_t *glyphs) const
{ if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{ for (auto g : *glyphs) if (get_class (g)) returntrue; returnfalse;
}
return hb_any (+ hb_iter (rangeRecord)
| hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
} bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{ if (klass == 0)
{ /* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
hb_codepoint_t last = HB_SET_VALUE_INVALID; auto it = hb_iter (rangeRecord); for (auto &range : it)
{ if (it->first == last + 1)
{
it++; continue;
}
if (!glyphs->next (&g)) break; if (g < range.first) returntrue;
g = range.last;
last = g;
} if (g != HB_SET_VALUE_INVALID && glyphs->next (&g)) returntrue; /* Fall through. */
} for (constauto &range : rangeRecord) if (range.value == klass && range.intersects (*glyphs)) returntrue; returnfalse;
}
void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
{ if (klass == 0)
{
hb_codepoint_t g = HB_SET_VALUE_INVALID; for (auto &range : rangeRecord)
{ if (!glyphs->next (&g)) goto done; while (g < range.first)
{
intersect_glyphs->add (g); if (!glyphs->next (&g)) goto done;
}
g = range.last;
} while (glyphs->next (&g))
intersect_glyphs->add (g);
done:
return;
}
unsigned count = rangeRecord.len; if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
{ for (auto g : *glyphs)
{ unsigned i; if (rangeRecord.as_array ().bfind (g, &i) &&
rangeRecord.arrayZ[i].value == klass)
intersect_glyphs->add (g);
} return;
}
for (auto &range : rangeRecord)
{ if (range.value != klass) continue;
unsigned end = range.last + 1; for (hb_codepoint_t g = range.first - 1;
glyphs->next (&g) && g < end;)
intersect_glyphs->add (g);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.