diff options
Diffstat (limited to 'thirdparty/harfbuzz')
156 files changed, 11033 insertions, 6679 deletions
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh new file mode 100644 index 0000000000..484f347468 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh @@ -0,0 +1,110 @@ +#ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH +#define OT_LAYOUT_GSUB_ALTERNATESET_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct AlternateSet +{ + protected: + Array16Of<HBGlyphID16> + alternates; /* Array of alternate GlyphIDs--in + * arbitrary order */ + public: + DEFINE_SIZE_ARRAY (2, alternates); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (alternates.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return hb_any (alternates, glyphs); } + + void closure (hb_closure_context_t *c) const + { c->output->add_array (alternates.arrayZ, alternates.len); } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { c->output->add_array (alternates.arrayZ, alternates.len); } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = alternates.len; + + if (unlikely (!count)) return_trace (false); + + hb_mask_t glyph_mask = c->buffer->cur().mask; + hb_mask_t lookup_mask = c->lookup_mask; + + /* Note: This breaks badly if two features enabled this lookup together. */ + unsigned int shift = hb_ctz (lookup_mask); + unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); + + /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */ + if (alt_index == HB_OT_MAP_MAX_VALUE && c->random) + { + /* Maybe we can do better than unsafe-to-break all; but since we are + * changing random state, it would be hard to track that. Good 'nough. */ + c->buffer->unsafe_to_break (0, c->buffer->len); + alt_index = c->random_number () % count + 1; + } + + if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); + + c->replace_glyph (alternates[alt_index - 1]); + + return_trace (true); + } + + unsigned + get_alternates (unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + if (alternates.len && alternate_count) + { + + alternates.sub_array (start_offset, alternate_count) + | hb_sink (hb_array (alternate_glyphs, *alternate_count)) + ; + } + return alternates.len; + } + + template <typename Iterator, + hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> + bool serialize (hb_serialize_context_t *c, + Iterator alts) + { + TRACE_SERIALIZE (this); + return_trace (alternates.serialize (c, alts)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (alternates) + | hb_filter (glyphset) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, it) && + out->alternates); + } +}; + +} +} +} + + +#endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh new file mode 100644 index 0000000000..e5d999261f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh @@ -0,0 +1,51 @@ +#ifndef OT_LAYOUT_GSUB_ALTERNATESUBST_HH +#define OT_LAYOUT_GSUB_ALTERNATESUBST_HH + +#include "AlternateSubstFormat1.hh" +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct AlternateSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + AlternateSubstFormat1 format1; + } u; + public: + + 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, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const HBGlyphID16> alternate_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (u.format))) return_trace (false); + unsigned int format = 1; + u.format = format; + switch (u.format) { + case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); + default:return_trace (false); + } + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_ALTERNATESUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh new file mode 100644 index 0000000000..af1cd7bedb --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -0,0 +1,128 @@ +#ifndef OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH + +#include "AlternateSet.hh" +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct AlternateSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Array16OfOffset16To<AlternateSet> + alternateSet; /* Array of AlternateSet tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (6, alternateSet); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + bool may_have_non_1to1 () const + { return false; } + + void closure (hb_closure_context_t *c) const + { + + hb_zip (this+coverage, alternateSet) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) + ; + + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, alternateSet) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); }) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + unsigned + get_glyph_alternates (hb_codepoint_t gid, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { return (this+alternateSet[(this+coverage).get_coverage (gid)]) + .get_alternates (start_offset, alternate_count, alternate_glyphs); } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + return_trace ((this+alternateSet[index]).apply (c)); + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const HBGlyphID16> alternate_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int alternate_len = alternate_len_list[i]; + if (unlikely (!alternateSet[i] + .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len)))) + return_trace (false); + alternate_glyphs_list += alternate_len; + } + return_trace (coverage.serialize_serialize (c, glyphs)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + 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; + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + hb_zip (this+coverage, alternateSet) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh new file mode 100644 index 0000000000..bbb88b222f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh @@ -0,0 +1,18 @@ +#ifndef OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH +#define OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH + +// TODO(garretrieger): move to new layout. +#include "../../../hb-ot-layout-gsubgpos.hh" +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct ChainContextSubst : ChainContext {}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh new file mode 100644 index 0000000000..f4c78a9f02 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh @@ -0,0 +1,21 @@ +#ifndef OT_LAYOUT_GSUB_COMMON_HH +#define OT_LAYOUT_GSUB_COMMON_HH + +#include "../../../hb-serialize.hh" +#include "../../../hb-ot-layout-gsubgpos.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; + +template<typename Iterator> +static void SingleSubst_serialize (hb_serialize_context_t *c, + Iterator it); + +} +} +} + +#endif /* OT_LAYOUT_GSUB_COMMON_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh new file mode 100644 index 0000000000..2af54e8ff4 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh @@ -0,0 +1,18 @@ +#ifndef OT_LAYOUT_GSUB_CONTEXTSUBST_HH +#define OT_LAYOUT_GSUB_CONTEXTSUBST_HH + +// TODO(garretrieger): move to new layout. +#include "../../../hb-ot-layout-gsubgpos.hh" +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct ContextSubst : Context {}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_CONTEXTSUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh new file mode 100644 index 0000000000..40a3ff439f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh @@ -0,0 +1,22 @@ +#ifndef OT_LAYOUT_GSUB_EXTENSIONSUBST_HH +#define OT_LAYOUT_GSUB_EXTENSIONSUBST_HH + +// TODO(garretrieger): move to new layout. +#include "../../../hb-ot-layout-gsubgpos.hh" +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct ExtensionSubst : Extension<ExtensionSubst> +{ + typedef struct SubstLookupSubTable SubTable; + bool is_reverse () const; +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_EXTENSIONSUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh new file mode 100644 index 0000000000..ad153ce8d7 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh @@ -0,0 +1,58 @@ +#ifndef OT_LAYOUT_GSUB_GSUB_HH +#define OT_LAYOUT_GSUB_GSUB_HH + +// TODO(garretrieger): move to new layout. +#include "../../../hb-ot-layout-gsubgpos.hh" +#include "Common.hh" +#include "SubstLookup.hh" + +using OT::Layout::GSUB::SubstLookup; + +namespace OT { +namespace Layout { +namespace GSUB { + +/* + * GSUB -- Glyph Substitution + * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub + */ + +struct GSUB : GSUBGPOS +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB; + + const SubstLookup& get_lookup (unsigned int i) const + { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); } + + bool subset (hb_subset_context_t *c) const + { + hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features); + return GSUBGPOS::subset<SubstLookup> (&l); + } + + bool sanitize (hb_sanitize_context_t *c) const + { return GSUBGPOS::sanitize<SubstLookup> (c); } + + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; + + void closure_lookups (hb_face_t *face, + const hb_set_t *glyphs, + hb_set_t *lookup_indexes /* IN/OUT */) const + { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); } + + typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t; +}; + + +} +} + +struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t { + GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {} +}; + + +} + +#endif /* OT_LAYOUT_GSUB_GSUB_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh new file mode 100644 index 0000000000..0448d925d1 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh @@ -0,0 +1,135 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURE_HH +#define OT_LAYOUT_GSUB_LIGATURE_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct Ligature +{ + protected: + HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */ + HeadlessArrayOf<HBGlyphID16> + component; /* Array of component GlyphIDs--start + * with the second component--ordered + * in writing direction */ + public: + DEFINE_SIZE_ARRAY (4, component); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return hb_all (component, glyphs); } + + void closure (hb_closure_context_t *c) const + { + if (!intersects (c->glyphs)) return; + c->output->add (ligGlyph); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + c->input->add_array (component.arrayZ, component.get_length ()); + c->output->add (ligGlyph); + } + + bool would_apply (hb_would_apply_context_t *c) const + { + if (c->len != component.lenP1) + return false; + + for (unsigned int i = 1; i < c->len; i++) + if (likely (c->glyphs[i] != component[i])) + return false; + + return true; + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = component.lenP1; + + if (unlikely (!count)) return_trace (false); + + /* Special-case to make it in-place and not consider this + * as a "ligated" substitution. */ + if (unlikely (count == 1)) + { + c->replace_glyph (ligGlyph); + return_trace (true); + } + + unsigned int total_component_count = 0; + + unsigned int match_end = 0; + unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; + + if (likely (!match_input (c, count, + &component[1], + match_glyph, + nullptr, + &match_end, + match_positions, + &total_component_count))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, match_end); + return_trace (false); + } + + ligate_input (c, + count, + match_positions, + match_end, + ligGlyph, + total_component_count); + + return_trace (true); + } + + template <typename Iterator, + hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> + bool serialize (hb_serialize_context_t *c, + hb_codepoint_t ligature, + Iterator components /* Starting from second */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + ligGlyph = ligature; + if (unlikely (!component.serialize (c, components))) return_trace (false); + return_trace (true); + } + + bool subset (hb_subset_context_t *c, unsigned coverage_idx) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); + // Ensure Coverage table is always packed after this. + c->serializer->add_virtual_link (coverage_idx); + + auto it = + + hb_iter (component) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, + glyph_map[ligGlyph], + it)); } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURE_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh new file mode 100644 index 0000000000..185b324b35 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh @@ -0,0 +1,118 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH +#define OT_LAYOUT_GSUB_LIGATURESET_HH + +#include "Common.hh" +#include "Ligature.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSet +{ + protected: + Array16OfOffset16To<Ligature> + ligature; /* Array LigatureSet tables + * ordered by preference */ + public: + DEFINE_SIZE_ARRAY (2, ligature); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (ligature.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) + | hb_any + ; + } + + void closure (hb_closure_context_t *c) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.closure (c); }) + ; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) + ; + } + + bool would_apply (hb_would_apply_context_t *c) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) + | hb_any + ; + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + { + const Ligature &lig = this+ligature[i]; + if (lig.apply (c)) return_trace (true); + } + + return_trace (false); + } + + bool serialize (hb_serialize_context_t *c, + hb_array_t<const HBGlyphID16> ligatures, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); + for (unsigned int i = 0; i < ligatures.length; i++) + { + unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); + if (unlikely (!ligature[i].serialize_serialize (c, + ligatures[i], + component_list.sub_array (0, component_count)))) + return_trace (false); + component_list += component_count; + } + return_trace (true); + } + + bool subset (hb_subset_context_t *c, unsigned coverage_idx) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (ligature) + | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) + | hb_drain + ; + + if (bool (out->ligature)) + // Ensure Coverage table is always packed after this. + c->serializer->add_virtual_link (coverage_idx); + + return_trace (bool (out->ligature)); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh new file mode 100644 index 0000000000..a029bf5e9f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh @@ -0,0 +1,59 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH +#define OT_LAYOUT_GSUB_LIGATURESUBST_HH + +#include "Common.hh" +#include "LigatureSubstFormat1.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + LigatureSubstFormat1 format1; + } u; + + public: + 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, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const HBGlyphID16> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (u.format))) return_trace (false); + unsigned int format = 1; + u.format = format; + switch (u.format) { + case 1: return_trace (u.format1.serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + ligatures_list, + component_count_list, + component_list)); + default:return_trace (false); + } + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh new file mode 100644 index 0000000000..19dfe98469 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -0,0 +1,165 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH + +#include "Common.hh" +#include "LigatureSet.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Array16OfOffset16To<LigatureSet> + ligatureSet; /* Array LigatureSet tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (6, ligatureSet); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return + + hb_zip (this+coverage, ligatureSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_) + { return (this+_).intersects (glyphs); }) + | hb_any + ; + } + + bool may_have_non_1to1 () const + { return true; } + + void closure (hb_closure_context_t *c) const + { + + hb_zip (this+coverage, ligatureSet) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) + ; + + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + + hb_zip (this+coverage, ligatureSet) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { + unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); + if (likely (index == NOT_COVERED)) return false; + + const LigatureSet &lig_set = this+ligatureSet[index]; + return lig_set.would_apply (c); + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + + unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + const LigatureSet &lig_set = this+ligatureSet[index]; + return_trace (lig_set.apply (c)); + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const HBGlyphID16> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < first_glyphs.length; i++) + { + unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; + if (unlikely (!ligatureSet[i] + .serialize_serialize (c, + ligatures_list.sub_array (0, ligature_count), + component_count_list.sub_array (0, ligature_count), + component_list))) return_trace (false); + ligatures_list += ligature_count; + component_count_list += ligature_count; + } + return_trace (coverage.serialize_serialize (c, first_glyphs)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + 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; + + // Due to a bug in some older versions of windows 7 the Coverage table must be + // packed after the LigatureSet and Ligature tables, so serialize Coverage first + // which places it last in the packed order. + hb_set_t new_coverage; + + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) + | hb_filter (glyphset, hb_first) + | hb_filter ([&] (const LigatureSet& _) { + return _.intersects (&glyphset); + }, hb_second) + | hb_map (hb_first) + | hb_sink (new_coverage); + + if (!c->serializer->push<Coverage> () + ->serialize (c->serializer, + + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) + { + c->serializer->pop_discard (); + return_trace (false); + } + + unsigned coverage_idx = c->serializer->pop_pack (); + c->serializer->add_link (out->coverage, coverage_idx); + + + hb_zip (this+coverage, ligatureSet) + | hb_filter (new_coverage, hb_first) + | hb_map (hb_second) + // to ensure that the repacker always orders the coverage table after the LigatureSet + // and LigatureSubtable's they will be linked to the Coverage table via a virtual link + // the coverage table object idx is passed down to facilitate this. + | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) + ; + + return_trace (bool (new_coverage)); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh new file mode 100644 index 0000000000..b289175504 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh @@ -0,0 +1,53 @@ +#ifndef OT_LAYOUT_GSUB_MULTIPLESUBST_HH +#define OT_LAYOUT_GSUB_MULTIPLESUBST_HH + +#include "Common.hh" +#include "MultipleSubstFormat1.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct MultipleSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + MultipleSubstFormat1 format1; + } u; + + public: + + 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, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const HBGlyphID16> substitute_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (u.format))) return_trace (false); + unsigned int format = 1; + u.format = format; + switch (u.format) { + case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); + default:return_trace (false); + } + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_MULTIPLESUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh new file mode 100644 index 0000000000..54c6dc8478 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -0,0 +1,120 @@ +#ifndef OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH + +#include "Common.hh" +#include "Sequence.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct MultipleSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Array16OfOffset16To<Sequence> + sequence; /* Array of Sequence tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (6, sequence); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + bool may_have_non_1to1 () const + { return true; } + + void closure (hb_closure_context_t *c) const + { + + hb_zip (this+coverage, sequence) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Sequence &_) { _.closure (c); }) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, sequence) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); }) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + return_trace ((this+sequence[index]).apply (c)); + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const HBGlyphID16> substitute_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int substitute_len = substitute_len_list[i]; + if (unlikely (!sequence[i] + .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len)))) + return_trace (false); + substitute_glyphs_list += substitute_len; + } + return_trace (coverage.serialize_serialize (c, glyphs)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + 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; + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + hb_zip (this+coverage, sequence) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->sequence, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } +}; + +} +} +} + + +#endif /* OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh new file mode 100644 index 0000000000..435d80fd31 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -0,0 +1,36 @@ +#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH +#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH + +#include "Common.hh" +#include "ReverseChainSingleSubstFormat1.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct ReverseChainSingleSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + ReverseChainSingleSubstFormat1 format1; + } u; + + public: + 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, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + +} +} +} + +#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh new file mode 100644 index 0000000000..7a79a9df25 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -0,0 +1,228 @@ +#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct ReverseChainSingleSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of table */ + Array16OfOffset16To<Coverage> + backtrack; /* Array of coverage tables + * in backtracking sequence, in glyph + * sequence order */ + Array16OfOffset16To<Coverage> + lookaheadX; /* Array of coverage tables + * in lookahead sequence, in glyph + * sequence order */ + Array16Of<HBGlyphID16> + substituteX; /* Array of substitute + * GlyphIDs--ordered by Coverage Index */ + public: + DEFINE_SIZE_MIN (10); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) + return_trace (false); + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + if (!lookahead.sanitize (c, this)) + return_trace (false); + const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); + return_trace (substitute.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+backtrack[i]).intersects (glyphs)) + return false; + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+lookahead[i]).intersects (glyphs)) + return false; + + return true; + } + + bool may_have_non_1to1 () const + { return false; } + + void closure (hb_closure_context_t *c) const + { + if (!intersects (c->glyphs)) return; + + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); + + + hb_zip (this+coverage, substitute) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_sink (c->output) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; + + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; + + const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); + count = substitute.len; + c->output->add_array (substitute.arrayZ, substitute.len); + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) + return_trace (false); /* No chaining to this type */ + + unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); + + if (unlikely (index >= substitute.len)) return_trace (false); + + unsigned int start_index = 0, end_index = 0; + if (match_backtrack (c, + backtrack.len, (HBUINT16 *) backtrack.arrayZ, + match_coverage, this, + &start_index) && + match_lookahead (c, + lookahead.len, (HBUINT16 *) lookahead.arrayZ, + match_coverage, this, + c->buffer->idx + 1, &end_index)) + { + c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); + c->replace_glyph_inplace (substitute[index]); + /* Note: We DON'T decrease buffer->idx. The main loop does it + * for us. This is useful for preventing surprises if someone + * calls us through a Context lookup. */ + return_trace (true); + } + else + { + c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); + return_trace (false); + } + } + + template<typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const + { + TRACE_SERIALIZE (this); + auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> (); + + if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) + return_trace (false); + + for (auto& offset : it) { + auto *o = out->serialize_append (c->serializer); + if (unlikely (!o) || !o->serialize_subset (c, offset, this)) + return_trace (false); + } + + return_trace (true); + } + + template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator, + hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)), + hb_requires (hb_is_iterator (BacktrackIterator)), + hb_requires (hb_is_iterator (LookaheadIterator))> + bool serialize (hb_subset_context_t *c, + Iterator coverage_subst_iter, + BacktrackIterator backtrack_iter, + LookaheadIterator lookahead_iter) const + { + TRACE_SERIALIZE (this); + + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->check_success (out))) return_trace (false); + if (unlikely (!c->serializer->embed (this->format))) return_trace (false); + if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); + + if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false); + if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false); + + auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> (); + auto substitutes = + + coverage_subst_iter + | hb_map (hb_second) + ; + + auto glyphs = + + coverage_subst_iter + | hb_map_retains_sorting (hb_first) + ; + if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes)))) + return_trace (false); + + if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs))) + return_trace (false); + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); + const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); + + auto it = + + hb_zip (this+coverage, substitute) + | hb_filter (glyphset, hb_first) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ())); + } +}; + +} +} +} + +#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh new file mode 100644 index 0000000000..ebd451e6ba --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh @@ -0,0 +1,103 @@ +#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH +#define OT_LAYOUT_GSUB_SEQUENCE_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct Sequence +{ + protected: + Array16Of<HBGlyphID16> + substitute; /* String of GlyphIDs to substitute */ + public: + DEFINE_SIZE_ARRAY (2, substitute); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (substitute.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return hb_all (substitute, glyphs); } + + void closure (hb_closure_context_t *c) const + { c->output->add_array (substitute.arrayZ, substitute.len); } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { c->output->add_array (substitute.arrayZ, substitute.len); } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = substitute.len; + + /* Special-case to make it in-place and not consider this + * as a "multiplied" substitution. */ + if (unlikely (count == 1)) + { + c->replace_glyph (substitute.arrayZ[0]); + return_trace (true); + } + /* Spec disallows this, but Uniscribe allows it. + * https://github.com/harfbuzz/harfbuzz/issues/253 */ + else if (unlikely (count == 0)) + { + c->buffer->delete_glyph (); + return_trace (true); + } + + unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? + HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; + unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur()); + + for (unsigned int i = 0; i < count; i++) + { + /* If is attached to a ligature, don't disturb that. + * https://github.com/harfbuzz/harfbuzz/issues/3069 */ + if (!lig_id) + _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); + c->output_glyph_for_component (substitute.arrayZ[i], klass); + } + c->buffer->skip_glyph (); + + return_trace (true); + } + + template <typename Iterator, + hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> + bool serialize (hb_serialize_context_t *c, + Iterator subst) + { + TRACE_SERIALIZE (this); + return_trace (substitute.serialize (c, subst)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + if (!intersects (&glyphset)) return_trace (false); + + auto it = + + hb_iter (substitute) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, it)); + } +}; + + +} +} +} + + +#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh new file mode 100644 index 0000000000..786428fe45 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh @@ -0,0 +1,75 @@ +#ifndef OT_LAYOUT_GSUB_SINGLESUBST_HH +#define OT_LAYOUT_GSUB_SINGLESUBST_HH + +#include "Common.hh" +#include "SingleSubstFormat1.hh" +#include "SingleSubstFormat2.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct SingleSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + SingleSubstFormat1 format1; + SingleSubstFormat2 format2; + } u; + + public: + + 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, std::forward<Ts> (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + template<typename Iterator, + hb_requires (hb_is_sorted_source_of (Iterator, + const hb_codepoint_pair_t))> + bool serialize (hb_serialize_context_t *c, + Iterator glyphs) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (u.format))) return_trace (false); + unsigned format = 2; + unsigned delta = 0; + if (glyphs) + { + format = 1; + auto get_delta = [=] (hb_codepoint_pair_t _) + { return (unsigned) (_.second - _.first) & 0xFFFF; }; + delta = get_delta (*glyphs); + if (!hb_all (++(+glyphs), delta, get_delta)) format = 2; + } + u.format = format; + switch (u.format) { + case 1: return_trace (u.format1.serialize (c, + + glyphs + | hb_map_retains_sorting (hb_first), + delta)); + case 2: return_trace (u.format2.serialize (c, glyphs)); + default:return_trace (false); + } + } +}; + +template<typename Iterator> +static void +SingleSubst_serialize (hb_serialize_context_t *c, + Iterator it) +{ c->start_embed<SingleSubst> ()->serialize (c, it); } + +} +} +} + +#endif /* OT_LAYOUT_GSUB_SINGLESUBST_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh new file mode 100644 index 0000000000..3c6b2954ce --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -0,0 +1,122 @@ +#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct SingleSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + HBUINT16 deltaGlyphID; /* Add to original GlyphID to get + * substitute GlyphID, modulo 0x10000 */ + + public: + DEFINE_SIZE_STATIC (6); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + bool may_have_non_1to1 () const + { return false; } + + void closure (hb_closure_context_t *c) const + { + unsigned d = deltaGlyphID; + + + hb_iter (this+coverage) + | hb_filter (c->parent_active_glyphs ()) + | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + | hb_sink (c->output) + ; + + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + unsigned d = deltaGlyphID; + + hb_iter (this+coverage) + | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + | hb_sink (c->output) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_codepoint_t glyph_id = c->buffer->cur().codepoint; + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) return_trace (false); + + /* According to the Adobe Annotated OpenType Suite, result is always + * limited to 16bit. */ + glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; + c->replace_glyph (glyph_id); + + return_trace (true); + } + + template<typename Iterator, + hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))> + bool serialize (hb_serialize_context_t *c, + Iterator glyphs, + unsigned delta) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false); + c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW); + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + hb_codepoint_t delta = deltaGlyphID; + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting ([&] (hb_codepoint_t g) { + return hb_codepoint_pair_t (g, + (g + delta) & 0xFFFF); }) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + bool ret = bool (it); + SingleSubst_serialize (c->serializer, it); + return_trace (ret); + } +}; + +} +} +} + + +#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh new file mode 100644 index 0000000000..df75bb52bb --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -0,0 +1,120 @@ +#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH +#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct SingleSubstFormat2 +{ + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Array16Of<HBGlyphID16> + substitute; /* Array of substitute + * GlyphIDs--ordered by Coverage Index */ + + public: + DEFINE_SIZE_ARRAY (6, substitute); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + bool may_have_non_1to1 () const + { return false; } + + void closure (hb_closure_context_t *c) const + { + + hb_zip (this+coverage, substitute) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_sink (c->output) + ; + + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, substitute) + | hb_map (hb_second) + | hb_sink (c->output) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + if (unlikely (index >= substitute.len)) return_trace (false); + + c->replace_glyph (substitute[index]); + + return_trace (true); + } + + template<typename Iterator, + hb_requires (hb_is_sorted_source_of (Iterator, + hb_codepoint_pair_t))> + bool serialize (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + auto substitutes = + + it + | hb_map (hb_second) + ; + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false); + if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false); + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_zip (this+coverage, substitute) + | hb_filter (glyphset, hb_first) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + bool ret = bool (it); + SingleSubst_serialize (c->serializer, it); + return_trace (ret); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh new file mode 100644 index 0000000000..3419b5a734 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh @@ -0,0 +1,224 @@ +#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH +#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH + +#include "Common.hh" +#include "SubstLookupSubTable.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct SubstLookup : Lookup +{ + typedef SubstLookupSubTable SubTable; + + bool sanitize (hb_sanitize_context_t *c) const + { return Lookup::sanitize<SubTable> (c); } + + const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } + + static inline bool lookup_type_is_reverse (unsigned int lookup_type) + { return lookup_type == SubTable::ReverseChainSingle; } + + bool is_reverse () const + { + unsigned int type = get_type (); + if (unlikely (type == SubTable::Extension)) + return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse (); + return lookup_type_is_reverse (type); + } + + bool may_have_non_1to1 () const + { + hb_have_non_1to1_context_t c; + return dispatch (&c); + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + return_trace (dispatch (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + + hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const + { + if (!c->should_visit_lookup (this_index)) + return hb_closure_context_t::default_return_value (); + + c->set_recurse_func (dispatch_closure_recurse_func); + + hb_closure_context_t::return_t ret = dispatch (c); + + c->flush (); + + return ret; + } + + hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const + { + if (c->is_lookup_visited (this_index)) + return hb_closure_lookups_context_t::default_return_value (); + + c->set_lookup_visited (this_index); + if (!intersects (c->glyphs)) + { + c->set_lookup_inactive (this_index); + return hb_closure_lookups_context_t::default_return_value (); + } + + c->set_recurse_func (dispatch_closure_lookups_recurse_func); + + hb_closure_lookups_context_t::return_t ret = dispatch (c); + return ret; + } + + hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const + { + c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); + return dispatch (c); + } + + template <typename set_t> + void collect_coverage (set_t *glyphs) const + { + hb_collect_coverage_context_t<set_t> c (glyphs); + dispatch (&c); + } + + bool would_apply (hb_would_apply_context_t *c, + const hb_ot_layout_lookup_accelerator_t *accel) const + { + if (unlikely (!c->len)) return false; + if (!accel->may_have (c->glyphs[0])) return false; + return dispatch (c); + } + + static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); + + bool serialize_single (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const HBGlyphID16> substitutes) + { + TRACE_SERIALIZE (this); + if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); + if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes))) + { + c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); + return_trace (true); + } + c->pop_discard (); + return_trace (false); + } + + bool serialize_multiple (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const HBGlyphID16> substitute_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); + if (c->push<SubTable> ()->u.multiple. + serialize (c, + glyphs, + substitute_len_list, + substitute_glyphs_list)) + { + c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); + return_trace (true); + } + c->pop_discard (); + return_trace (false); + } + + bool serialize_alternate (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_sorted_array_t<const HBGlyphID16> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const HBGlyphID16> alternate_glyphs_list) + { + TRACE_SERIALIZE (this); + if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); + + if (c->push<SubTable> ()->u.alternate. + serialize (c, + glyphs, + alternate_len_list, + alternate_glyphs_list)) + { + c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); + return_trace (true); + } + c->pop_discard (); + return_trace (false); + } + + bool serialize_ligature (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_sorted_array_t<const HBGlyphID16> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const HBGlyphID16> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); + if (c->push<SubTable> ()->u.ligature. + serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + ligatures_list, + component_count_list, + component_list)) + { + c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); + return_trace (true); + } + c->pop_discard (); + return_trace (false); + } + + template <typename context_t> + static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + + static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index); + + static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) + { + if (!c->should_visit_lookup (lookup_index)) + return hb_empty_t (); + + hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); + + /* While in theory we should flush here, it will cause timeouts because a recursive + * lookup can keep growing the glyph set. Skip, and outer loop will retry up to + * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */ + //c->flush (); + + return ret; + } + + HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index); + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } + + bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh new file mode 100644 index 0000000000..53e963e2a2 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh @@ -0,0 +1,77 @@ +#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH +#define OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH + +#include "Common.hh" +#include "SingleSubst.hh" +#include "MultipleSubst.hh" +#include "AlternateSubst.hh" +#include "LigatureSubst.hh" +#include "ContextSubst.hh" +#include "ChainContextSubst.hh" +#include "ExtensionSubst.hh" +#include "ReverseChainSingleSubst.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct SubstLookupSubTable +{ + friend struct ::OT::Lookup; + friend struct SubstLookup; + + protected: + union { + SingleSubst single; + MultipleSubst multiple; + AlternateSubst alternate; + LigatureSubst ligature; + ContextSubst context; + ChainContextSubst chainContext; + ExtensionSubst extension; + ReverseChainSingleSubst reverseChainContextSingle; + } u; + public: + DEFINE_SIZE_MIN (0); + + enum Type { + Single = 1, + Multiple = 2, + Alternate = 3, + Ligature = 4, + Context = 5, + ChainContext = 6, + Extension = 7, + ReverseChainSingle = 8 + }; + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const + { + TRACE_DISPATCH (this, lookup_type); + switch (lookup_type) { + case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...)); + case Multiple: return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...)); + case Alternate: return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...)); + case Ligature: return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...)); + case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...)); + case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...)); + case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...)); + case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...)); + default: return_trace (c->default_return_value ()); + } + } + + bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c, lookup_type); + } +}; + + +} +} +} + +#endif /* HB_OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh index 1dcbe92904..1db0f1df92 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh @@ -839,7 +839,7 @@ struct StateTableDriver } if (!c->in_place) - buffer->swap_buffers (); + buffer->sync (); } public: diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh index d745c11431..0bf9bd2912 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh @@ -146,7 +146,7 @@ struct DuctileGlyphAction HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. * This would normally be 0x64756374 ('duct'), * but you may use any axis the font contains. */ - HBFixed minimumLimit; /* The lowest value for the ductility axis tha + HBFixed minimumLimit; /* The lowest value for the ductility axis that * still yields an acceptable appearance. Normally * this will be 1.0. */ HBFixed noStretchValue; /* This is the default value that corresponds to diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh index 2f99510925..b77c1f4d44 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh @@ -1038,12 +1038,12 @@ struct Chain goto skip; if (reverse) - _hb_ot_layout_reverse_graphemes (c->buffer); + c->buffer->reverse (); subtable->apply (c); if (reverse) - _hb_ot_layout_reverse_graphemes (c->buffer); + c->buffer->reverse (); (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.cc b/thirdparty/harfbuzz/src/hb-aat-layout.cc index e2d4de2ccd..caff204d67 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout.cc +++ b/thirdparty/harfbuzz/src/hb-aat-layout.cc @@ -108,7 +108,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] = {HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS}, {HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7}, {HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, - {HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF}, + {HB_TAG ('h','i','s','t'), (hb_aat_layout_feature_type_t) 40, (hb_aat_layout_feature_selector_t) 0, (hb_aat_layout_feature_selector_t) 1}, {HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF}, {HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF}, {HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION}, @@ -170,6 +170,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] = {HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF}, {HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, {HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF}, + {HB_TAG ('v','r','t','r'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, (hb_aat_layout_feature_selector_t) 2, (hb_aat_layout_feature_selector_t) 3}, {HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF}, }; diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh index 446d87e28b..05b4df52f1 100644 --- a/thirdparty/harfbuzz/src/hb-algs.hh +++ b/thirdparty/harfbuzz/src/hb-algs.hh @@ -36,6 +36,7 @@ #include <algorithm> #include <initializer_list> +#include <functional> #include <new> /* @@ -149,10 +150,26 @@ struct BEInt<Type, 4> uint8_t ((V >> 16) & 0xFF), uint8_t ((V >> 8) & 0xFF), uint8_t ((V ) & 0xFF)} {} - constexpr operator Type () const { return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); } + + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + constexpr operator Type () const { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap32 (((packed_uint32_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint32_t *) this)->v; +#endif +#else + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); +#endif + } private: uint8_t v[4]; }; @@ -210,12 +227,23 @@ struct } HB_FUNCOBJ (hb_bool); +template <typename T> +static inline +constexpr T hb_coerce (const T v) { return v; } +template <typename T, typename V, + hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && std::is_pointer<V>::value)> +static inline +constexpr T hb_coerce (const V v) { return *v; } + struct { private: template <typename T> constexpr auto - impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + + template <typename T> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) template <typename T, hb_enable_if (std::is_integral<T>::value)> constexpr auto @@ -435,23 +463,29 @@ struct private: template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<3>) const HB_AUTO_RETURN ( std::forward<T2> (v2).cmp (std::forward<T1> (v1)) == 0 ) template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN ( std::forward<T1> (v1).cmp (std::forward<T2> (v2)) == 0 ) template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN ( std::forward<T1> (v1) == std::forward<T2> (v2) ) + template <typename T1, typename T2> auto + impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN + ( + std::forward<T2> (v2) == std::forward<T1> (v1) + ) + public: template <typename T1, typename T2> auto @@ -472,11 +506,15 @@ struct hb_pair_t typedef T2 second_t; typedef hb_pair_t<T1, T2> pair_t; + template <typename U1 = T1, typename U2 = T2, + hb_enable_if (std::is_default_constructible<U1>::value && + std::is_default_constructible<U2>::value)> + hb_pair_t () : first (), second () {} hb_pair_t (T1 a, T2 b) : first (a), second (b) {} template <typename Q1, typename Q2, hb_enable_if (hb_is_convertible (T1, Q1) && - hb_is_convertible (T2, T2))> + hb_is_convertible (T2, Q2))> operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); } hb_pair_t<T1, T2> reverse () const @@ -870,7 +908,7 @@ hb_bsearch_impl (unsigned *pos, /* Out */ #pragma GCC diagnostic ignored "-Wcast-align" V* p = (V*) (((const char *) base) + (mid * stride)); #pragma GCC diagnostic pop - int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...); + int c = compar ((const void *) std::addressof (key), (const void *) p, ds...); if (c < 0) max = mid - 1; else if (c > 0) diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh index 0beffb078f..1963698cf7 100644 --- a/thirdparty/harfbuzz/src/hb-array.hh +++ b/thirdparty/harfbuzz/src/hb-array.hh @@ -346,7 +346,7 @@ struct hb_sorted_array_t : unsigned int i; return bfind (x, &i) ? &this->arrayZ[i] : not_found; } - template <typename T> + template <typename T, typename ...Ts> const Type *bsearch (const T &x, const Type *not_found = nullptr) const { unsigned int i; @@ -384,15 +384,16 @@ struct hb_sorted_array_t : } return false; } - template <typename T> - bool bsearch_impl (const T &x, unsigned *pos) const + template <typename T, typename ...Ts> + bool bsearch_impl (const T &x, unsigned *pos, Ts... ds) const { return hb_bsearch_impl (pos, x, this->arrayZ, this->length, sizeof (Type), - _hb_cmp_method<T, Type>); + _hb_cmp_method<T, Type, Ts...>, + ds...); } }; template <typename T> inline hb_sorted_array_t<T> @@ -403,7 +404,7 @@ hb_sorted_array (T (&array_)[length_]) { return hb_sorted_array_t<T> (array_); } template <typename T> -bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const +inline bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const { if (o.length != this->length) return false; for (unsigned int i = 0; i < this->length; i++) { @@ -411,8 +412,18 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const } return true; } - -/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */ +template <> +inline bool hb_array_t<const char>::operator == (const hb_array_t<const char> &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} +template <> +inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const unsigned char> &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} template <> inline uint32_t hb_array_t<const char>::hash () const { @@ -421,7 +432,6 @@ inline uint32_t hb_array_t<const char>::hash () const { current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); return current; } - template <> inline uint32_t hb_array_t<const unsigned char>::hash () const { uint32_t current = 0; diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh index d466af8b60..5b313bf59c 100644 --- a/thirdparty/harfbuzz/src/hb-bimap.hh +++ b/thirdparty/harfbuzz/src/hb-bimap.hh @@ -33,26 +33,18 @@ /* Bi-directional map */ struct hb_bimap_t { - /* XXX(remove) */ - void init () - { - forw_map.init (); - back_map.init (); - } - - /* XXX(remove) */ - void fini () - { - forw_map.fini (); - back_map.fini (); - } - void reset () { forw_map.reset (); back_map.reset (); } + void resize (unsigned pop) + { + forw_map.resize (pop); + back_map.resize (pop); + } + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } void set (hb_codepoint_t lhs, hb_codepoint_t rhs) diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh index 263be3d044..cbe918ee40 100644 --- a/thirdparty/harfbuzz/src/hb-bit-page.hh +++ b/thirdparty/harfbuzz/src/hb-bit-page.hh @@ -40,11 +40,18 @@ struct hb_bit_page_t bool is_empty () const { - for (unsigned int i = 0; i < len (); i++) + for (unsigned i = 0; i < len (); i++) if (v[i]) return false; return true; } + uint32_t hash () const + { + uint32_t h = 0; + for (unsigned i = 0; i < len (); i++) + h = h * 31 + hb_hash (v[i]); + return h; + } void add (hb_codepoint_t g) { elt (g) |= mask (g); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } @@ -86,6 +93,72 @@ struct hb_bit_page_t void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) { if (v) add_range (a, b); else del_range (a, b); } + + // Writes out page values to the array p. Returns the number of values + // written. At most size codepoints will be written. + unsigned int write (uint32_t base, + unsigned int start_value, + hb_codepoint_t *p, + unsigned int size) const + { + unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_bit = start_value & ELT_MASK; + unsigned int count = 0; + for (unsigned i = start_v; i < len () && count < size; i++) + { + elt_t bits = v[i]; + uint32_t v_base = base | (i << ELT_BITS_LOG_2); + for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) + { + if ((elt_t(1) << j) & bits) { + *p++ = v_base | j; + count++; + } + } + start_bit = 0; + } + return count; + } + + // Writes out the values NOT in this page to the array p. Returns the + // number of values written. At most size codepoints will be written. + // Returns the number of codepoints written. next_value holds the next value + // that should be written (if not present in this page). This is used to fill + // any missing value gaps between this page and the previous page, if any. + // next_value is updated to one more than the last value present in this page. + unsigned int write_inverted (uint32_t base, + unsigned int start_value, + hb_codepoint_t *p, + unsigned int size, + hb_codepoint_t *next_value) const + { + unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_bit = start_value & ELT_MASK; + unsigned int count = 0; + for (unsigned i = start_v; i < len () && count < size; i++) + { + elt_t bits = v[i]; + uint32_t v_offset = i << ELT_BITS_LOG_2; + for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) + { + if ((elt_t(1) << j) & bits) + { + hb_codepoint_t value = base | v_offset | j; + // Emit all the missing values from next_value up to value - 1. + for (hb_codepoint_t k = *next_value; k < value && count < size; k++) + { + *p++ = k; + count++; + } + // Skip over this value; + *next_value = value + 1; + } + } + start_bit = 0; + } + return count; + } + bool is_equal (const hb_bit_page_t &other) const { return 0 == hb_memcmp (&v, &other.v, sizeof (v)); @@ -179,6 +252,9 @@ struct hb_bit_page_t typedef unsigned long long elt_t; static constexpr unsigned PAGE_BITS = 512; static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); + static constexpr unsigned PAGE_BITS_LOG_2 = 9; + static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, ""); + static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1; static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; } @@ -186,7 +262,10 @@ struct hb_bit_page_t typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t; static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8; + static constexpr unsigned ELT_BITS_LOG_2 = 6; + static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, ""); static constexpr unsigned ELT_MASK = ELT_BITS - 1; + static constexpr unsigned BITS = sizeof (vector_t) * 8; static constexpr unsigned MASK = BITS - 1; static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, ""); diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh index 0832b0fc23..caea47d8d3 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh @@ -38,10 +38,10 @@ struct hb_bit_set_invertible_t bool inverted = false; hb_bit_set_invertible_t () = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default; + hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); } hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; } friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) { if (likely (!a.s.successful || !b.s.successful)) @@ -56,6 +56,7 @@ struct hb_bit_set_invertible_t bool in_error () const { return s.in_error (); } explicit operator bool () const { return !is_empty (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); @@ -79,6 +80,8 @@ struct hb_bit_set_invertible_t next (&v); return v == INVALID; } + uint32_t hash () const { return s.hash () ^ inverted; } + hb_codepoint_t get_min () const { hb_codepoint_t v = INVALID; @@ -323,6 +326,14 @@ struct hb_bit_set_invertible_t return true; } + unsigned int next_many (hb_codepoint_t codepoint, + hb_codepoint_t *out, + unsigned int size) const + { + return inverted ? s.next_many_inverted (codepoint, out, size) + : s.next_many (codepoint, out, size); + } + static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID; /* diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh index a471ee48b5..11a4359dc9 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set.hh @@ -97,6 +97,13 @@ struct hb_bit_set_t return true; } + void alloc (unsigned sz) + { + sz >>= (page_t::PAGE_BITS_LOG_2 - 1); + pages.alloc (sz); + page_map.alloc (sz); + } + void reset () { successful = true; @@ -119,6 +126,14 @@ struct hb_bit_set_t } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (auto &map : page_map) + h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]); + return h; + } + private: void dirty () { population = UINT_MAX; } public: @@ -203,7 +218,7 @@ struct hb_bit_set_t bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T)) { if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ - if (!count) return true; + if (unlikely (!count)) return true; dirty (); hb_codepoint_t g = *array; hb_codepoint_t last_g = g; @@ -222,7 +237,7 @@ struct hb_bit_set_t if (v || page) /* The v check is to optimize out the page check if v is true. */ page->add (g); - array = (const T *) ((const char *) array + stride); + array = &StructAtOffsetUnaligned<T> (array, stride); count--; } while (count && (g = *array, g < end)); @@ -341,15 +356,14 @@ struct hb_bit_set_t return; population = other.population; - /* TODO switch to vector operator =. */ - hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size); - hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size); + page_map = other.page_map; + pages = other.pages; } bool is_equal (const hb_bit_set_t &other) const { if (has_population () && other.has_population () && - get_population () != other.get_population ()) + population != other.population) return false; unsigned int na = pages.length; @@ -377,7 +391,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - get_population () != larger_set.get_population ()) + population != larger_set.population) return false; uint32_t spi = 0; @@ -700,6 +714,99 @@ struct hb_bit_set_t return true; } + unsigned int next_many (hb_codepoint_t codepoint, + hb_codepoint_t *out, + unsigned int size) const + { + // By default, start at the first bit of the first page of values. + unsigned int start_page = 0; + unsigned int start_page_value = 0; + if (unlikely (codepoint != INVALID)) + { + const auto* page_map_array = page_map.arrayZ; + unsigned int major = get_major (codepoint); + unsigned int i = last_page_lookup; + if (unlikely (i >= page_map.length || page_map_array[i].major != major)) + { + page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); + if (i >= page_map.length) + return 0; // codepoint is greater than our max element. + } + start_page = i; + start_page_value = page_remainder (codepoint + 1); + if (unlikely (start_page_value == 0)) + { + // The export-after value was last in the page. Start on next page. + start_page++; + start_page_value = 0; + } + } + + unsigned int initial_size = size; + for (unsigned int i = start_page; i < page_map.length && size; i++) + { + uint32_t base = major_start (page_map[i].major); + unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size); + out += n; + size -= n; + start_page_value = 0; + } + return initial_size - size; + } + + unsigned int next_many_inverted (hb_codepoint_t codepoint, + hb_codepoint_t *out, + unsigned int size) const + { + unsigned int initial_size = size; + // By default, start at the first bit of the first page of values. + unsigned int start_page = 0; + unsigned int start_page_value = 0; + if (unlikely (codepoint != INVALID)) + { + const auto* page_map_array = page_map.arrayZ; + unsigned int major = get_major (codepoint); + unsigned int i = last_page_lookup; + if (unlikely (i >= page_map.length || page_map_array[i].major != major)) + { + page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST); + if (unlikely (i >= page_map.length)) + { + // codepoint is greater than our max element. + while (++codepoint != INVALID && size) + { + *out++ = codepoint; + size--; + } + return initial_size - size; + } + } + start_page = i; + start_page_value = page_remainder (codepoint + 1); + if (unlikely (start_page_value == 0)) + { + // The export-after value was last in the page. Start on next page. + start_page++; + start_page_value = 0; + } + } + + hb_codepoint_t next_value = codepoint + 1; + for (unsigned int i=start_page; i<page_map.length && size; i++) + { + uint32_t base = major_start (page_map[i].major); + unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value); + out += n; + size -= n; + start_page_value = 0; + } + while (next_value < HB_SET_VALUE_INVALID && size) { + *out++ = next_value++; + size--; + } + return initial_size - size; + } + bool has_population () const { return population != UINT_MAX; } unsigned int get_population () const { @@ -781,7 +888,19 @@ struct hb_bit_set_t page_t *page_for (hb_codepoint_t g, bool insert = false) { - page_map_t map = {get_major (g), pages.length}; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + if (likely (last_page_lookup < page_map.length)) + { + auto &cached_page = page_map.arrayZ[last_page_lookup]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t map = {major, pages.length}; unsigned int i; if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST)) { @@ -797,20 +916,37 @@ struct hb_bit_set_t (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } + + last_page_lookup = i; return &pages[page_map[i].index]; } const page_t *page_for (hb_codepoint_t g) const { - page_map_t key = {get_major (g)}; - const page_map_t *found = page_map.bsearch (key); - if (found) - return &pages[found->index]; - return nullptr; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + if (likely (last_page_lookup < page_map.length)) + { + auto &cached_page = page_map.arrayZ[last_page_lookup]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t key = {major}; + unsigned int i; + if (!page_map.bfind (key, &i)) + return nullptr; + + last_page_lookup = i; + return &pages[page_map[i].index]; } page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } - unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; } - hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; } + unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; } + unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; } + hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; } }; diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc index f120002d17..65e44c7f6a 100644 --- a/thirdparty/harfbuzz/src/hb-blob.cc +++ b/thirdparty/harfbuzz/src/hb-blob.cc @@ -631,7 +631,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) Allison Lortie permission but changed a lot to suit our need. */ #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return hb_blob_get_empty (); + if (unlikely (!file)) return nullptr; int fd = open (file_name, O_RDONLY | O_BINARY, 0); if (unlikely (fd == -1)) goto fail_without_close; @@ -671,7 +671,7 @@ fail_without_close: #elif defined(_WIN32) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return hb_blob_get_empty (); + if (unlikely (!file)) return nullptr; HANDLE fd; unsigned int size = strlen (file_name) + 1; diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh index b599e9667c..06a605e225 100644 --- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh +++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh @@ -478,7 +478,7 @@ _resume: case 18: #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -535,7 +535,7 @@ _resume: case 16: #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -635,7 +635,7 @@ _resume: } #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -645,7 +645,7 @@ _resume: case 17: #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -674,7 +674,7 @@ _resume: } #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -701,7 +701,7 @@ _resume: } #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -733,7 +733,7 @@ _again: case 16: #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) @@ -820,7 +820,7 @@ _again: } #line 58 "hb-buffer-deserialize-text.rl" { - /* TODO Unescape delimeters. */ + /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc new file mode 100644 index 0000000000..dea2c11c35 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc @@ -0,0 +1,422 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#ifndef HB_NO_BUFFER_VERIFY + +#include "hb-buffer.hh" + + +#define BUFFER_VERIFY_ERROR "buffer verify error: " +static inline void +buffer_verify_error (hb_buffer_t *buffer, + hb_font_t *font, + const char *fmt, + ...) HB_PRINTF_FUNC(3, 4); + +static inline void +buffer_verify_error (hb_buffer_t *buffer, + hb_font_t *font, + const char *fmt, + ...) +{ + va_list ap; + va_start (ap, fmt); + if (buffer->messaging ()) + { + buffer->message_impl (font, fmt, ap); + } + else + { + fprintf (stderr, "harfbuzz "); + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + } + va_end (ap); +} + +static bool +buffer_verify_monotone (hb_buffer_t *buffer, + hb_font_t *font) +{ + /* Check that clusters are monotone. */ + if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES || + buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + for (unsigned int i = 1; i < num_glyphs; i++) + if (info[i-1].cluster != info[i].cluster && + (info[i-1].cluster < info[i].cluster) != is_forward) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone."); + return false; + } + } + + return true; +} + +static bool +buffer_verify_unsafe_to_break (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && + buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + /* Cannot perform this check without monotone clusters. */ + return true; + } + + /* Check that breaking up shaping at safe-to-break is indeed safe. */ + + hb_buffer_t *fragment = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + unsigned int num_chars; + hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); + + /* Chop text and shape fragments. */ + bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + unsigned int start = 0; + unsigned int text_start = forward ? 0 : num_chars; + unsigned int text_end = text_start; + for (unsigned int end = 1; end < num_glyphs + 1; end++) + { + if (end < num_glyphs && + (info[end].cluster == info[end-1].cluster || + info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)) + continue; + + /* Shape segment corresponding to glyphs start..end. */ + if (end == num_glyphs) + { + if (forward) + text_end = num_chars; + else + text_start = 0; + } + else + { + if (forward) + { + unsigned int cluster = info[end].cluster; + while (text_end < num_chars && text[text_end].cluster < cluster) + text_end++; + } + else + { + unsigned int cluster = info[end - 1].cluster; + while (text_start && text[text_start - 1].cluster >= cluster) + text_start--; + } + } + assert (text_start < text_end); + + if (0) + printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + + hb_buffer_clear_contents (fragment); + + hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); + if (0 < text_start) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + if (text_end < num_chars) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + hb_buffer_set_flags (fragment, flags); + + hb_buffer_append (fragment, text_buffer, text_start, text_end); + if (!hb_shape_full (font, fragment, features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + return false; + } + hb_buffer_append (reconstruction, fragment, 0, -1); + + start = end; + if (forward) + text_start = text_end; + else + text_end = text_start; + } + + bool ret = true; + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); + ret = false; + + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } + + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + + return ret; +} + +static bool +buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && + buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + /* Cannot perform this check without monotone clusters. */ + return true; + } + + /* Check that shuffling up text before shaping at safe-to-concat points + * is indeed safe. */ + + /* This is what we do: + * + * 1. We shape text once. Then segment the text at all the safe-to-concat + * points; + * + * 2. Then we create two buffers, one containing all the even segments and + * one all the odd segments. + * + * 3. Because all these segments were safe-to-concat at both ends, we + * expect that concatenating them and shaping should NOT change the + * shaping results of each segment. As such, we expect that after + * shaping the two buffers, we still get cluster boundaries at the + * segment boundaries, and that those all are safe-to-concat points. + * Moreover, that there are NOT any safe-to-concat points within the + * segments. + * + * 4. Finally, we reconstruct the shaping results of the original text by + * simply interleaving the shaping results of the segments from the two + * buffers, and assert that the total shaping results is the same as + * the one from original buffer in step 1. + */ + + hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer), + hb_buffer_create_similar (buffer)}; + hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + hb_segment_properties_t props; + hb_buffer_get_segment_properties (buffer, &props); + hb_buffer_set_segment_properties (fragments[0], &props); + hb_buffer_set_segment_properties (fragments[1], &props); + hb_buffer_set_segment_properties (reconstruction, &props); + + unsigned num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + unsigned num_chars; + hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); + + bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + + if (!forward) + hb_buffer_reverse (buffer); + + /* + * Split text into segments and collect into to fragment streams. + */ + { + unsigned fragment_idx = 0; + unsigned start = 0; + unsigned text_start = 0; + unsigned text_end = 0; + for (unsigned end = 1; end < num_glyphs + 1; end++) + { + if (end < num_glyphs && + (info[end].cluster == info[end-1].cluster || + info[end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT)) + continue; + + /* Accumulate segment corresponding to glyphs start..end. */ + if (end == num_glyphs) + text_end = num_chars; + else + { + unsigned cluster = info[end].cluster; + while (text_end < num_chars && text[text_end].cluster < cluster) + text_end++; + } + assert (text_start < text_end); + + if (0) + printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + +#if 0 + hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); + if (0 < text_start) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + if (text_end < num_chars) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + hb_buffer_set_flags (fragment, flags); +#endif + + hb_buffer_append (fragments[fragment_idx], text_buffer, text_start, text_end); + + start = end; + text_start = text_end; + fragment_idx = 1 - fragment_idx; + } + } + + bool ret = true; + hb_buffer_diff_flags_t diff; + + /* + * Shape the two fragment streams. + */ + if (!hb_shape_full (font, fragments[0], features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + ret = false; + goto out; + } + if (!hb_shape_full (font, fragments[1], features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + ret = false; + goto out; + } + + if (!forward) + { + hb_buffer_reverse (fragments[0]); + hb_buffer_reverse (fragments[1]); + } + + /* + * Reconstruct results. + */ + { + unsigned fragment_idx = 0; + unsigned fragment_start[2] {0, 0}; + unsigned fragment_num_glyphs[2]; + hb_glyph_info_t *fragment_info[2]; + for (unsigned i = 0; i < 2; i++) + fragment_info[i] = hb_buffer_get_glyph_infos (fragments[i], &fragment_num_glyphs[i]); + while (fragment_start[0] < fragment_num_glyphs[0] || + fragment_start[1] < fragment_num_glyphs[1]) + { + unsigned fragment_end = fragment_start[fragment_idx] + 1; + while (fragment_end < fragment_num_glyphs[fragment_idx] && + (fragment_info[fragment_idx][fragment_end].cluster == fragment_info[fragment_idx][fragment_end - 1].cluster || + fragment_info[fragment_idx][fragment_end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT)) + fragment_end++; + + hb_buffer_append (reconstruction, fragments[fragment_idx], fragment_start[fragment_idx], fragment_end); + + fragment_start[fragment_idx] = fragment_end; + fragment_idx = 1 - fragment_idx; + } + } + + if (!forward) + { + hb_buffer_reverse (buffer); + hb_buffer_reverse (reconstruction); + } + + /* + * Diff results. + */ + diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); + ret = false; + + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } + + +out: + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragments[0]); + hb_buffer_destroy (fragments[1]); + + return ret; +} + +bool +hb_buffer_t::verify (hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + bool ret = true; + if (!buffer_verify_monotone (this, font)) + ret = false; + if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers)) + ret = false; + if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 && + !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers)) + ret = false; + if (!ret) + { + unsigned len = text_buffer->len; + hb_vector_t<char> bytes; + if (likely (bytes.resize (len * 10 + 16))) + { + hb_buffer_serialize_unicode (text_buffer, + 0, len, + bytes.arrayZ, bytes.length, + &len, + HB_BUFFER_SERIALIZE_FORMAT_TEXT, + HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS); + buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ); + } + } + return ret; +} + + +#endif diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc index be3161a54d..6a9ee3ccc8 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.cc +++ b/thirdparty/harfbuzz/src/hb-buffer.cc @@ -86,7 +86,46 @@ hb_segment_properties_hash (const hb_segment_properties_t *p) (intptr_t) (p->language); } +/** + * hb_segment_properties_overlay: + * @p: #hb_segment_properties_t to fill in. + * @src: #hb_segment_properties_t to fill in from. + * + * Fills in missing fields of @p from @src in a considered manner. + * + * First, if @p does not have direction set, direction is copied from @src. + * + * Next, if @p and @src have the same direction (which can be unset), if @p + * does not have script set, script is copied from @src. + * + * Finally, if @p and @src have the same direction and script (which either + * can be unset), if @p does not have language set, language is copied from + * @src. + * + * Since: 3.3.0 + **/ +void +hb_segment_properties_overlay (hb_segment_properties_t *p, + const hb_segment_properties_t *src) +{ + if (unlikely (!p || !src)) + return; + if (!p->direction) + p->direction = src->direction; + + if (p->direction != src->direction) + return; + + if (!p->script) + p->script = src->script; + + if (p->script != src->script) + return; + + if (!p->language) + p->language = src->language; +} /* Here is how the buffer works internally: * @@ -96,14 +135,14 @@ hb_segment_properties_hash (const hb_segment_properties_t *p) * As an optimization, both info and out_info may point to the * same piece of memory, which is owned by info. This remains the * case as long as out_len doesn't exceed i at any time. - * In that case, swap_buffers() is mostly no-op and the glyph operations + * In that case, sync() is mostly no-op and the glyph operations * operate mostly in-place. * * As soon as out_info gets longer than info, out_info is moved over * to an alternate buffer (which we reuse the pos buffer for), and its * current contents (out_len entries) are copied to the new place. * - * This should all remain transparent to the user. swap_buffers() then + * This should all remain transparent to the user. sync() then * switches info over to out_info and does housekeeping. */ @@ -217,11 +256,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size) /* HarfBuzz-Internal API */ void +hb_buffer_t::similar (const hb_buffer_t &src) +{ + hb_unicode_funcs_destroy (unicode); + unicode = hb_unicode_funcs_reference (src.unicode); + flags = src.flags; + cluster_level = src.cluster_level; + replacement = src.invisible; + invisible = src.invisible; + not_found = src.not_found; +} + +void hb_buffer_t::reset () { hb_unicode_funcs_destroy (unicode); unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); flags = HB_BUFFER_FLAG_DEFAULT; + cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; invisible = 0; not_found = 0; @@ -232,11 +284,10 @@ hb_buffer_t::reset () void hb_buffer_t::clear () { + content_type = HB_BUFFER_CONTENT_TYPE_INVALID; hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; props = default_props; - scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - content_type = HB_BUFFER_CONTENT_TYPE_INVALID; successful = true; have_output = false; have_positions = false; @@ -246,15 +297,42 @@ hb_buffer_t::clear () out_len = 0; out_info = info; - serial = 0; - memset (context, 0, sizeof context); memset (context_len, 0, sizeof context_len); deallocate_var_all (); + serial = 0; + scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; } void +hb_buffer_t::enter () +{ + deallocate_var_all (); + serial = 0; + scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) + { + max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR, + (unsigned) HB_BUFFER_MAX_LEN_MIN); + } + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR))) + { + max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR, + (unsigned) HB_BUFFER_MAX_OPS_MIN); + } +} +void +hb_buffer_t::leave () +{ + max_len = HB_BUFFER_MAX_LEN_DEFAULT; + max_ops = HB_BUFFER_MAX_OPS_DEFAULT; + deallocate_var_all (); + serial = 0; +} + + +void hb_buffer_t::add (hb_codepoint_t codepoint, unsigned int cluster) { @@ -307,7 +385,7 @@ hb_buffer_t::clear_positions () } void -hb_buffer_t::swap_buffers () +hb_buffer_t::sync () { assert (have_output); @@ -326,6 +404,7 @@ hb_buffer_t::swap_buffers () reset: have_output = false; out_len = 0; + out_info = info; idx = 0; } @@ -494,33 +573,6 @@ done: } void -hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end) -{ - unsigned int cluster = UINT_MAX; - cluster = _infos_find_min_cluster (info, start, end, cluster); - _unsafe_to_break_set_mask (info, start, end, cluster); -} -void -hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end) -{ - if (!have_output) - { - unsafe_to_break_impl (start, end); - return; - } - - assert (start <= out_len); - assert (idx <= end); - - unsigned int cluster = UINT_MAX; - cluster = _infos_find_min_cluster (out_info, start, out_len, cluster); - cluster = _infos_find_min_cluster (info, idx, end, cluster); - - _unsafe_to_break_set_mask (out_info, start, out_len, cluster); - _unsafe_to_break_set_mask (info, idx, end, cluster); -} - -void hb_buffer_t::guess_segment_properties () { assert_unicode (); @@ -565,12 +617,11 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, 0, /* invisible */ 0, /* not_found */ - HB_BUFFER_SCRATCH_FLAG_DEFAULT, - HB_BUFFER_MAX_LEN_DEFAULT, - HB_BUFFER_MAX_OPS_DEFAULT, + HB_BUFFER_CONTENT_TYPE_INVALID, HB_SEGMENT_PROPERTIES_DEFAULT, + false, /* successful */ false, /* have_output */ true /* have_positions */ @@ -610,6 +661,46 @@ hb_buffer_create () } /** + * hb_buffer_create_similar: + * @src: An #hb_buffer_t + * + * Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only + * difference is that the buffer is configured similarly to @src. + * + * Return value: (transfer full): + * A newly allocated #hb_buffer_t, similar to hb_buffer_create(). + * + * Since: 3.3.0 + **/ +hb_buffer_t * +hb_buffer_create_similar (const hb_buffer_t *src) +{ + hb_buffer_t *buffer = hb_buffer_create (); + + buffer->similar (*src); + + return buffer; +} + +/** + * hb_buffer_reset: + * @buffer: An #hb_buffer_t + * + * Resets the buffer to its initial status, as if it was just newly created + * with hb_buffer_create(). + * + * Since: 0.9.2 + **/ +void +hb_buffer_reset (hb_buffer_t *buffer) +{ + if (unlikely (hb_object_is_immutable (buffer))) + return; + + buffer->reset (); +} + +/** * hb_buffer_get_empty: * * Fetches an empty #hb_buffer_t. @@ -1157,24 +1248,6 @@ hb_buffer_get_not_found_glyph (hb_buffer_t *buffer) /** - * hb_buffer_reset: - * @buffer: An #hb_buffer_t - * - * Resets the buffer to its initial status, as if it was just newly created - * with hb_buffer_create(). - * - * Since: 0.9.2 - **/ -void -hb_buffer_reset (hb_buffer_t *buffer) -{ - if (unlikely (hb_object_is_immutable (buffer))) - return; - - buffer->reset (); -} - -/** * hb_buffer_clear_contents: * @buffer: An #hb_buffer_t * @@ -1716,7 +1789,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, **/ HB_EXTERN void hb_buffer_append (hb_buffer_t *buffer, - hb_buffer_t *source, + const hb_buffer_t *source, unsigned int start, unsigned int end) { @@ -1749,6 +1822,8 @@ hb_buffer_append (hb_buffer_t *buffer, if (!buffer->have_positions && source->have_positions) buffer->clear_positions (); + hb_segment_properties_overlay (&buffer->props, &source->props); + memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h index a183cb9d4a..14aaa5e1f5 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.h +++ b/thirdparty/harfbuzz/src/hb-buffer.h @@ -76,18 +76,72 @@ typedef struct hb_glyph_info_t { * @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the * beginning of the cluster this glyph is part of, * then both sides need to be re-shaped, as the - * result might be different. On the flip side, - * it means that when this flag is not present, - * then it's safe to break the glyph-run at the - * beginning of this cluster, and the two sides - * represent the exact same result one would get - * if breaking input text at the beginning of - * this cluster and shaping the two sides - * separately. This can be used to optimize - * paragraph layout, by avoiding re-shaping - * of each line after line-breaking, or limiting - * the reshaping to a small piece around the - * breaking point only. + * result might be different. + * On the flip side, it means that when this + * flag is not present, then it is safe to break + * the glyph-run at the beginning of this + * cluster, and the two sides will represent the + * exact same result one would get if breaking + * input text at the beginning of this cluster + * and shaping the two sides separately. + * This can be used to optimize paragraph + * layout, by avoiding re-shaping of each line + * after line-breaking. + * @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT: Indicates that if input text is changed on one + * side of the beginning of the cluster this glyph + * is part of, then the shaping results for the + * other side might change. + * Note that the absence of this flag will NOT by + * itself mean that it IS safe to concat text. + * Only two pieces of text both of which clear of + * this flag can be concatenated safely. + * This can be used to optimize paragraph + * layout, by avoiding re-shaping of each line + * after line-breaking, by limiting the + * reshaping to a small piece around the + * breaking positin only, even if the breaking + * position carries the + * #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when + * hyphenation or other text transformation + * happens at line-break position, in the following + * way: + * 1. Iterate back from the line-break position + * until the first cluster start position that is + * NOT unsafe-to-concat, 2. shape the segment from + * there till the end of line, 3. check whether the + * resulting glyph-run also is clear of the + * unsafe-to-concat at its start-of-text position; + * if it is, just splice it into place and the line + * is shaped; If not, move on to a position further + * back that is clear of unsafe-to-concat and retry + * from there, and repeat. + * At the start of next line a similar algorithm can + * be implemented. That is: 1. Iterate forward from + * the line-break position until the first cluster + * start position that is NOT unsafe-to-concat, 2. + * shape the segment from beginning of the line to + * that position, 3. check whether the resulting + * glyph-run also is clear of the unsafe-to-concat + * at its end-of-text position; if it is, just splice + * it into place and the beginning is shaped; If not, + * move on to a position further forward that is clear + * of unsafe-to-concat and retry up to there, and repeat. + * A slight complication will arise in the + * implementation of the algorithm above, + * because while our buffer API has a way to + * return flags for position corresponding to + * start-of-text, there is currently no position + * corresponding to end-of-text. This limitation + * can be alleviated by shaping more text than needed + * and looking for unsafe-to-concat flag within text + * clusters. + * The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will + * always imply this flag. + * To use this flag, you must enable the buffer flag + * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during + * shaping, otherwise the buffer flag will not be + * reliably produced. + * Since: 4.0.0 * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags. * * Flags for #hb_glyph_info_t. @@ -96,8 +150,9 @@ typedef struct hb_glyph_info_t { */ typedef enum { /*< flags >*/ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, + HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002, - HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */ + HB_GLYPH_FLAG_DEFINED = 0x00000003 /* OR of all defined flags */ } hb_glyph_flags_t; HB_EXTERN hb_glyph_flags_t @@ -170,6 +225,9 @@ hb_segment_properties_equal (const hb_segment_properties_t *a, HB_EXTERN unsigned int hb_segment_properties_hash (const hb_segment_properties_t *p); +HB_EXTERN void +hb_segment_properties_overlay (hb_segment_properties_t *p, + const hb_segment_properties_t *src); /** @@ -185,6 +243,13 @@ HB_EXTERN hb_buffer_t * hb_buffer_create (void); HB_EXTERN hb_buffer_t * +hb_buffer_create_similar (const hb_buffer_t *src); + +HB_EXTERN void +hb_buffer_reset (hb_buffer_t *buffer); + + +HB_EXTERN hb_buffer_t * hb_buffer_get_empty (void); HB_EXTERN hb_buffer_t * @@ -295,7 +360,19 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE: * flag indicating that a dotted circle should * not be inserted in the rendering of incorrect - * character sequences (such at <0905 093E>). Since: 2.4 + * character sequences (such at <0905 093E>). Since: 2.4.0 + * @HB_BUFFER_FLAG_VERIFY: + * flag indicating that the hb_shape() call and its variants + * should perform various verification processes on the results + * of the shaping operation on the buffer. If the verification + * fails, then either a buffer message is sent, if a message + * handler is installed on the buffer, or a message is written + * to standard error. In either case, the shaping result might + * be modified to show the failed output. Since: 3.4.0 + * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT: + * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT + * glyph-flag should be produced by the shaper. By default + * it will not be produced since it incurs a cost. Since: 4.0.0 * * Flags for #hb_buffer_t. * @@ -307,7 +384,9 @@ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u, HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u, - HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u + HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u, + HB_BUFFER_FLAG_VERIFY = 0x00000020u, + HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u } hb_buffer_flags_t; HB_EXTERN void @@ -391,8 +470,9 @@ HB_EXTERN hb_codepoint_t hb_buffer_get_not_found_glyph (hb_buffer_t *buffer); -HB_EXTERN void -hb_buffer_reset (hb_buffer_t *buffer); +/* + * Content API. + */ HB_EXTERN void hb_buffer_clear_contents (hb_buffer_t *buffer); @@ -460,7 +540,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, HB_EXTERN void hb_buffer_append (hb_buffer_t *buffer, - hb_buffer_t *source, + const hb_buffer_t *source, unsigned int start, unsigned int end); @@ -557,24 +637,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, HB_EXTERN unsigned int hb_buffer_serialize_unicode (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags); + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); HB_EXTERN unsigned int hb_buffer_serialize (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags); + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); HB_EXTERN hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, @@ -586,10 +666,10 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, HB_EXTERN hb_bool_t hb_buffer_deserialize_unicode (hb_buffer_t *buffer, - const char *buf, - int buf_len, - const char **end_ptr, - hb_buffer_serialize_format_t format); + const char *buf, + int buf_len, + const char **end_ptr, + hb_buffer_serialize_format_t format); diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh index 0f8140f1b3..bc6992905e 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.hh +++ b/thirdparty/harfbuzz/src/hb-buffer.hh @@ -67,8 +67,8 @@ enum hb_buffer_scratch_flags_t { HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u, HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u, HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u, - HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u, - HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u, + HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u, + HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u, /* Reserved for complex shapers' internal use. */ HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u, @@ -87,18 +87,21 @@ struct hb_buffer_t { hb_object_header_t header; - /* Information about how the text in the buffer should be treated */ + /* + * Information about how the text in the buffer should be treated. + */ + hb_unicode_funcs_t *unicode; /* Unicode functions */ hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_cluster_level_t cluster_level; hb_codepoint_t replacement; /* U+FFFD or something else. */ hb_codepoint_t invisible; /* 0 or something else. */ hb_codepoint_t not_found; /* 0 or something else. */ - hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ - unsigned int max_len; /* Maximum allowed len. */ - int max_ops; /* Maximum allowed operations. */ - /* Buffer contents */ + /* + * Buffer contents + */ + hb_buffer_content_type_t content_type; hb_segment_properties_t props; /* Script, language, direction */ @@ -115,8 +118,6 @@ struct hb_buffer_t hb_glyph_info_t *out_info; hb_glyph_position_t *pos; - unsigned int serial; - /* Text before / after the main buffer contents. * Always in Unicode, and ordered outward. * Index 0 is for "pre-context", 1 for "post-context". */ @@ -124,7 +125,25 @@ struct hb_buffer_t hb_codepoint_t context[2][CONTEXT_LENGTH]; unsigned int context_len[2]; - /* Debugging API */ + + /* + * Managed by enter / leave + */ + +#ifndef HB_NDEBUG + uint8_t allocated_var_bits; +#endif + uint8_t serial; + hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ + unsigned int max_len; /* Maximum allowed len. */ + int max_ops; /* Maximum allowed operations. */ + /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ + + + /* + * Messaging callback + */ + #ifndef HB_NO_BUFFER_MESSAGE hb_buffer_message_func_t message_func; void *message_data; @@ -134,11 +153,6 @@ struct hb_buffer_t static constexpr unsigned message_depth = 0u; #endif - /* Internal debugging. */ - /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ -#ifndef HB_NDEBUG - uint8_t allocated_var_bits; -#endif /* Methods */ @@ -190,12 +204,31 @@ struct hb_buffer_t hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); + /* Called around shape() */ + HB_INTERNAL void enter (); + HB_INTERNAL void leave (); + +#ifndef HB_NO_BUFFER_VERIFY + HB_INTERNAL +#endif + bool verify (hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +#ifndef HB_NO_BUFFER_VERIFY + ; +#else + { return true; } +#endif + unsigned int backtrack_len () const { return have_output ? out_len : idx; } unsigned int lookahead_len () const { return len - idx; } - unsigned int next_serial () { return serial++; } + uint8_t next_serial () { return ++serial ? serial : ++serial; } HB_INTERNAL void add (hb_codepoint_t codepoint, unsigned int cluster); @@ -252,7 +285,7 @@ struct hb_buffer_t HB_INTERNAL void guess_segment_properties (); - HB_INTERNAL void swap_buffers (); + HB_INTERNAL void sync (); HB_INTERNAL void clear_output (); HB_INTERNAL void clear_positions (); @@ -366,15 +399,87 @@ struct hb_buffer_t /* Merge clusters for deleting current glyph, and skip it. */ HB_INTERNAL void delete_glyph (); - void unsafe_to_break (unsigned int start, - unsigned int end) + + /* Adds glyph flags in mask to infos with clusters between start and end. + * The start index will be from out-buffer if from_out_buffer is true. + * If interior is true, then the cluster having the minimum value is skipped. */ + void _set_glyph_flags (hb_mask_t mask, + unsigned start = 0, + unsigned end = (unsigned) -1, + bool interior = false, + bool from_out_buffer = false) { - if (end - start < 2) + end = hb_min (end, len); + + if (interior && !from_out_buffer && end - start < 2) return; - unsafe_to_break_impl (start, end); + + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + + if (!from_out_buffer || !have_output) + { + if (!interior) + { + for (unsigned i = start; i < end; i++) + info[i].mask |= mask; + } + else + { + unsigned cluster = _infos_find_min_cluster (info, start, end); + _infos_set_glyph_flags (info, start, end, cluster, mask); + } + } + else + { + assert (start <= out_len); + assert (idx <= end); + + if (!interior) + { + for (unsigned i = start; i < out_len; i++) + out_info[i].mask |= mask; + for (unsigned i = idx; i < end; i++) + info[i].mask |= mask; + } + else + { + unsigned cluster = _infos_find_min_cluster (info, idx, end); + cluster = _infos_find_min_cluster (out_info, start, out_len, cluster); + + _infos_set_glyph_flags (out_info, start, out_len, cluster, mask); + _infos_set_glyph_flags (info, idx, end, cluster, mask); + } + } + } + + void unsafe_to_break (unsigned int start = 0, unsigned int end = -1) + { + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true); + } + void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1) + { + if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) + return; + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true); + } + void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1) + { + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true, true); + } + void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1) + { + if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) + return; + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + false, true); } - HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end); - HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end); /* Internal methods */ @@ -465,36 +570,31 @@ struct hb_buffer_t set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0) { if (inf.cluster != cluster) - { - if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) - inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - else - inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - } + inf.mask = (inf.mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED); inf.cluster = cluster; } - + void + _infos_set_glyph_flags (hb_glyph_info_t *infos, + unsigned int start, unsigned int end, + unsigned int cluster, + hb_mask_t mask) + { + for (unsigned int i = start; i < end; i++) + if (cluster != infos[i].cluster) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i].mask |= mask; + } + } static unsigned _infos_find_min_cluster (const hb_glyph_info_t *infos, unsigned start, unsigned end, - unsigned cluster) + unsigned cluster = UINT_MAX) { for (unsigned int i = start; i < end; i++) cluster = hb_min (cluster, infos[i].cluster); return cluster; } - void - _unsafe_to_break_set_mask (hb_glyph_info_t *infos, - unsigned int start, unsigned int end, - unsigned int cluster) - { - for (unsigned int i = start; i < end; i++) - if (cluster != infos[i].cluster) - { - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK; - infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - } - } void clear_glyph_flags (hb_mask_t mask = 0) { diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh index c251e2d0ed..5c2cb060a4 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh @@ -217,9 +217,6 @@ inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: struct number_t { - void init () { set_real (0.0); } - void fini () {} - void set_int (int v) { value = v; } int to_int () const { return value; } @@ -245,12 +242,15 @@ struct number_t } protected: - double value; + double value = 0.; }; /* byte string */ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> { + hb_ubytes_t as_ubytes (unsigned l) const + { return hb_ubytes_t ((const unsigned char *) this, l); } + // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) template <typename T, typename V> static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value) @@ -277,33 +277,10 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> /* Defining null_size allows a Null object may be created. Should be safe because: * A descendent struct Dict uses a Null pointer to indicate a missing table, * checked before access. - * byte_str_t, a wrapper struct pairing a byte pointer along with its length, always - * checks the length before access. A Null pointer is used as the initial pointer - * along with zero length by the default ctor. */ DEFINE_SIZE_MIN(0); }; -/* Holder of a section of byte string within a CFFIndex entry */ -struct byte_str_t : hb_ubytes_t -{ - byte_str_t () - : hb_ubytes_t () {} - byte_str_t (const UnsizedByteStr& s, unsigned int l) - : hb_ubytes_t ((const unsigned char*)&s, l) {} - byte_str_t (const unsigned char *s, unsigned int l) - : hb_ubytes_t (s, l) {} - byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */ - : hb_ubytes_t (ub) {} - - /* sub-string */ - byte_str_t sub_str (unsigned int offset, unsigned int len_) const - { return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); } - - bool check_limit (unsigned int offset, unsigned int count) const - { return (offset + count <= length); } -}; - /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { @@ -311,17 +288,17 @@ struct byte_str_ref_t void init () { - str = byte_str_t (); + str = hb_ubytes_t (); offset = 0; error = false; } void fini () {} - byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0) + byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) : str (str_), offset (offset_), error (false) {} - void reset (const byte_str_t &str_, unsigned int offset_ = 0) + void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; offset = offset_; @@ -337,14 +314,14 @@ struct byte_str_ref_t return str[offset + i]; } - /* Conversion to byte_str_t */ - operator byte_str_t () const { return str.sub_str (offset, str.length - offset); } + /* Conversion to hb_ubytes_t */ + operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } - byte_str_t sub_str (unsigned int offset_, unsigned int len_) const - { return str.sub_str (offset_, len_); } + hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const + { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && str.check_limit (offset, count)); } + { return (!in_error () && offset + count <= str.length); } void inc (unsigned int count=1) { if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) @@ -361,46 +338,39 @@ struct byte_str_ref_t void set_error () { error = true; } bool in_error () const { return error; } - byte_str_t str; + hb_ubytes_t str; unsigned int offset; /* beginning of the sub-string within str */ protected: bool error; }; -typedef hb_vector_t<byte_str_t> byte_str_array_t; +using byte_str_array_t = hb_vector_t<hb_ubytes_t>; /* stack */ template <typename ELEM, int LIMIT> struct cff_stack_t { - void init () - { - error = false; - count = 0; - elements.init (); - elements.resize (kSizeLimit); - for (unsigned int i = 0; i < elements.length; i++) - elements[i].init (); - } - void fini () { elements.fini_deep (); } - ELEM& operator [] (unsigned int i) { - if (unlikely (i >= count)) set_error (); + if (unlikely (i >= count)) + { + set_error (); + return Crap (ELEM); + } return elements[i]; } void push (const ELEM &v) { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) elements[count++] = v; else set_error (); } ELEM &push () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) return elements[count++]; else { @@ -429,7 +399,7 @@ struct cff_stack_t const ELEM& peek () { - if (unlikely (count < 0)) + if (unlikely (count == 0)) { set_error (); return Null (ELEM); @@ -439,7 +409,7 @@ struct cff_stack_t void unpop () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) count++; else set_error (); @@ -447,18 +417,19 @@ struct cff_stack_t void clear () { count = 0; } - bool in_error () const { return (error || elements.in_error ()); } + bool in_error () const { return (error); } void set_error () { error = true; } unsigned int get_count () const { return count; } bool is_empty () const { return !count; } - static constexpr unsigned kSizeLimit = LIMIT; + hb_array_t<const ELEM> sub_array (unsigned start, unsigned length) const + { return hb_array_t<const ELEM> (elements).sub_array (start, length); } - protected: - bool error; - unsigned int count; - hb_vector_t<ELEM> elements; + private: + bool error = false; + unsigned int count = 0; + ELEM elements[LIMIT]; }; /* argument stack */ @@ -513,9 +484,6 @@ struct arg_stack_t : cff_stack_t<ARG, 513> return true; } - hb_array_t<const ARG> get_subarray (unsigned int start) const - { return S::elements.sub_array (start); } - private: typedef cff_stack_t<ARG, 513> S; }; @@ -523,11 +491,8 @@ struct arg_stack_t : cff_stack_t<ARG, 513> /* an operator prefixed by its operands in a byte string */ struct op_str_t { - void init () {} - void fini () {} - + hb_ubytes_t str; op_code_t op; - byte_str_t str; }; /* base of OP_SERIALIZER */ @@ -553,13 +518,18 @@ struct parsed_values_t opStart = 0; values.init (); } - void fini () { values.fini_deep (); } + void fini () { values.fini (); } + + void alloc (unsigned n) + { + values.alloc (n); + } void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) { VAL *val = values.push (); val->op = op; - val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart); + val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart); opStart = str_ref.offset; } @@ -567,14 +537,14 @@ struct parsed_values_t { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart); + val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); opStart = str_ref.offset; } bool has_op (op_code_t op) const { - for (unsigned int i = 0; i < get_count (); i++) - if (get_value (i).op == op) return true; + for (const auto& v : values) + if (v.op == op) return true; return false; } @@ -589,14 +559,11 @@ struct parsed_values_t template <typename ARG=number_t> struct interp_env_t { - void init (const byte_str_t &str_) + interp_env_t () {} + interp_env_t (const hb_ubytes_t &str_) { str_ref.reset (str_); - argStack.init (); - error = false; } - void fini () { argStack.fini (); } - bool in_error () const { return error || str_ref.in_error () || argStack.in_error (); } @@ -630,10 +597,10 @@ struct interp_env_t arg_stack_t<ARG> argStack; protected: - bool error; + bool error = false; }; -typedef interp_env_t<> num_interp_env_t; +using num_interp_env_t = interp_env_t<>; template <typename ARG=number_t> struct opset_t @@ -676,11 +643,8 @@ struct opset_t template <typename ENV> struct interpreter_t { - ~interpreter_t() { fini (); } - - void fini () { env.fini (); } - - ENV env; + interpreter_t (ENV& env_) : env (env_) {} + ENV& env; }; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh index 52d778ffe2..2983ae54a1 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh @@ -79,10 +79,10 @@ struct biased_subrs_t unsigned int get_count () const { return subrs ? subrs->count : 0; } unsigned int get_bias () const { return bias; } - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (!subrs || index >= subrs->count)) - return Null (byte_str_t); + return hb_ubytes_t (); else return (*subrs)[index]; } @@ -94,12 +94,6 @@ struct biased_subrs_t struct point_t { - void init () - { - x.init (); - y.init (); - } - void set_int (int _x, int _y) { x.set_int (_x); @@ -118,26 +112,21 @@ struct point_t template <typename ARG, typename SUBRS> struct cs_interp_env_t : interp_env_t<ARG> { - void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) + cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) : + interp_env_t<ARG> (str) { - interp_env_t<ARG>::init (str); - context.init (str, CSType_CharString); seen_moveto = true; seen_hintmask = false; hstem_count = 0; vstem_count = 0; hintmask_size = 0; - pt.init (); - callStack.init (); + pt.set_int (0, 0); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); } - void fini () + ~cs_interp_env_t () { - interp_env_t<ARG>::fini (); - - callStack.fini (); globalSubrs.fini (); localSubrs.fini (); } @@ -841,7 +830,6 @@ struct path_procs_t if (likely (env.argStack.get_count () == 11)) { point_t d; - d.init (); for (unsigned int i = 0; i < 10; i += 2) d.move (env.eval_arg (i), env.eval_arg (i+1)); @@ -887,6 +875,8 @@ struct path_procs_t template <typename ENV, typename OPSET, typename PARAM> struct cs_interpreter_t : interpreter_t<ENV> { + cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} + bool interpret (PARAM& param) { SUPER::env.set_endchar (false); diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh index a520ca3bce..79fe9b42c5 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh @@ -179,6 +179,8 @@ struct top_dict_opset_t : dict_opset_t template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> struct dict_interpreter_t : interpreter_t<ENV> { + dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} + bool interpret (PARAM& param) { param.init (); diff --git a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh index 1c8762c172..b306c2ecc9 100644 --- a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh @@ -38,17 +38,15 @@ typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs> { template <typename ACC> - void init (const byte_str_t &str, ACC &acc, unsigned int fd) + cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); processed_width = false; has_width = false; arg_start = 0; in_seac = false; } - void fini () { SUPER::fini (); } - void set_width (bool has_width_) { if (likely (!processed_width && (SUPER::argStack.get_count () > 0))) @@ -154,7 +152,7 @@ struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM }; template <typename OPSET, typename PARAM> -struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {}; +using cff1_cs_interpreter_t = cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM>; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh index d961566447..d0b9e7b086 100644 --- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh @@ -35,18 +35,6 @@ using namespace OT; struct blend_arg_t : number_t { - void init () - { - number_t::init (); - deltas.init (); - } - - void fini () - { - number_t::fini (); - deltas.fini_deep (); - } - void set_int (int v) { reset_blends (); number_t::set_int (v); } void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); } void set_real (double v) { reset_blends (); number_t::set_real (v); } @@ -76,14 +64,14 @@ struct blend_arg_t : number_t typedef interp_env_t<blend_arg_t> BlendInterpEnv; typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t; -struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> +template <typename ELEM> +struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs> { template <typename ACC> - void init (const byte_str_t &str, ACC &acc, unsigned int fd, - const int *coords_=nullptr, unsigned int num_coords_=0) + cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); - coords = coords_; num_coords = num_coords_; varStore = acc.varStore; @@ -112,18 +100,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> return OpCode_return; } - const blend_arg_t& eval_arg (unsigned int i) + const ELEM& eval_arg (unsigned int i) { - blend_arg_t &arg = argStack[i]; - blend_arg (arg); - return arg; + return SUPER::argStack[i]; } - const blend_arg_t& pop_arg () + const ELEM& pop_arg () { - blend_arg_t &arg = argStack.pop (); - blend_arg (arg); - return arg; + return SUPER::argStack.pop (); } void process_blend () @@ -134,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> if (do_blend) { if (unlikely (!scalars.resize (region_count))) - set_error (); + SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, &scalars[0], region_count); @@ -145,10 +129,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> void process_vsindex () { - unsigned int index = argStack.pop_uint (); + unsigned int index = SUPER::argStack.pop_uint (); if (unlikely (seen_vsindex () || seen_blend)) { - set_error (); + SUPER::set_error (); } else { @@ -163,22 +147,18 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> void set_ivs (unsigned int ivs_) { ivs = ivs_; } bool seen_vsindex () const { return seen_vsindex_; } - protected: - void blend_arg (blend_arg_t &arg) + double blend_deltas (hb_array_t<const ELEM> deltas) const { - if (do_blend && arg.blending ()) + double v = 0; + if (do_blend) { - if (likely (scalars.length == arg.deltas.length)) + if (likely (scalars.length == deltas.length)) { - double v = arg.to_real (); for (unsigned int i = 0; i < scalars.length; i++) - { - v += (double)scalars[i] * arg.deltas[i].to_real (); - } - arg.set_real (v); - arg.deltas.resize (0); + v += (double) scalars[i] * deltas[i].to_real (); } } + return v; } protected: @@ -192,22 +172,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> bool seen_vsindex_; bool seen_blend; - typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER; + typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER; }; -template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>> -struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> +template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>> +struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { switch (op) { case OpCode_callsubr: case OpCode_callgsubr: - /* a subroutine number shoudln't be a blended value */ + /* a subroutine number shouldn't be a blended value */ +#if 0 if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); break; } +#endif SUPER::process_op (op, env, param); break; @@ -216,11 +198,13 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA break; case OpCode_vsindexcs: +#if 0 if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); break; } +#endif OPSET::process_vsindex (env, param); break; @@ -229,7 +213,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA } } - static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) + template <typename T = ELEM, + hb_enable_if (hb_is_same (T, blend_arg_t))> + static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env, + ELEM &arg, + const hb_array_t<const ELEM> blends, + unsigned n, unsigned i) + { + arg.set_blends (n, i, blends.length, blends); + } + template <typename T = ELEM, + hb_enable_if (!hb_is_same (T, blend_arg_t))> + static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env, + ELEM &arg, + const hb_array_t<const ELEM> blends, + unsigned n, unsigned i) + { + arg.set_real (arg.to_real () + env.blend_deltas (blends)); + } + + static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { unsigned int n, k; @@ -246,26 +249,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA } for (unsigned int i = 0; i < n; i++) { - const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k)); - env.argStack[start + i].set_blends (n, i, k, blends); + const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k); + process_arg_blend (env, env.argStack[start + i], blends, n, i); } /* pop off blend values leaving default values now adorned with blend values */ env.argStack.pop (k * n); } - static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) + static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { env.process_vsindex (); env.clear_args (); } private: - typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER; + typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER; }; -template <typename OPSET, typename PARAM> -struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {}; +template <typename OPSET, typename PARAM, typename ELEM> +using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc index 26c8ad0f49..41229b9183 100644 --- a/thirdparty/harfbuzz/src/hb-common.cc +++ b/thirdparty/harfbuzz/src/hb-common.cc @@ -29,10 +29,31 @@ #include "hb.hh" #include "hb-machinery.hh" +#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE)) +#define HB_NO_SETLOCALE 1 +#endif + +#ifndef HB_NO_SETLOCALE + #include <locale.h> +#ifdef HAVE_XLOCALE_H +#include <xlocale.h> // Needed on BSD/OS X for uselocale +#endif + +#ifdef WIN32 +#define hb_locale_t _locale_t +#else +#define hb_locale_t locale_t +#endif +#define hb_setlocale setlocale +#define hb_uselocale uselocale + +#else + +#define hb_locale_t void * +#define hb_setlocale(Category, Locale) "C" +#define hb_uselocale(Locale) ((hb_locale_t) 0) -#ifdef HB_NO_SETLOCALE -#define setlocale(Category, Locale) "C" #endif /** @@ -122,7 +143,7 @@ hb_tag_from_string (const char *str, int len) * @tag: #hb_tag_t to convert * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string * - * Converts an #hb_tag_t to a string and returns it in @buf. + * Converts an #hb_tag_t to a string and returns it in @buf. * Strings will be four characters long. * * Since: 0.9.5 @@ -151,13 +172,13 @@ const char direction_strings[][4] = { * @str: (array length=len) (element-type uint8_t): String to convert * @len: Length of @str, or -1 if it is %NULL-terminated * - * Converts a string to an #hb_direction_t. + * Converts a string to an #hb_direction_t. * * Matching is loose and applies only to the first letter. For * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR. * * Unmatched strings will return #HB_DIRECTION_INVALID. - * + * * Return value: The #hb_direction_t matching @str * * Since: 0.9.2 @@ -413,7 +434,7 @@ hb_language_get_default () hb_language_t language = default_language; if (unlikely (language == HB_LANGUAGE_INVALID)) { - language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1); + language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1); (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language); } @@ -1039,6 +1060,47 @@ hb_variation_from_string (const char *str, int len, return false; } +#ifndef HB_NO_SETLOCALE + +static inline void free_static_C_locale (); + +static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>, + hb_C_locale_lazy_loader_t> +{ + static hb_locale_t create () + { + hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL); + if (!l) + return l; + + hb_atexit (free_static_C_locale); + + return l; + } + static void destroy (hb_locale_t l) + { + freelocale (l); + } + static hb_locale_t get_null () + { + return (hb_locale_t) 0; + } +} static_C_locale; + +static inline +void free_static_C_locale () +{ + static_C_locale.free_instance (); +} + +static hb_locale_t +get_C_locale () +{ + return static_C_locale.get_unconst (); +} + +#endif + /** * hb_variation_to_string: * @variation: an #hb_variation_t to convert @@ -1064,7 +1126,11 @@ hb_variation_to_string (hb_variation_t *variation, while (len && s[len - 1] == ' ') len--; s[len++] = '='; + + hb_locale_t oldlocale HB_UNUSED; + oldlocale = hb_uselocale (get_C_locale ()); len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); + (void) hb_uselocale (oldlocale); assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h index 0384117a4d..7b897a6c51 100644 --- a/thirdparty/harfbuzz/src/hb-common.h +++ b/thirdparty/harfbuzz/src/hb-common.h @@ -130,6 +130,16 @@ typedef union _hb_var_int_t { int8_t i8[4]; } hb_var_int_t; +typedef union _hb_var_num_t { + float f; + uint32_t u32; + int32_t i32; + uint16_t u16[2]; + int16_t i16[2]; + uint8_t u8[4]; + int8_t i8[4]; +} hb_var_num_t; + /* hb_tag_t */ @@ -481,6 +491,7 @@ hb_language_get_default (void); * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0 * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 + * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -697,6 +708,11 @@ typedef enum HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/ HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/ + /* + * Since 3.4.0 + */ + HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh index 7d00d9088a..4b46dea938 100644 --- a/thirdparty/harfbuzz/src/hb-config.hh +++ b/thirdparty/harfbuzz/src/hb-config.hh @@ -55,6 +55,7 @@ #define HB_NO_ATEXIT #define HB_NO_BUFFER_MESSAGE #define HB_NO_BUFFER_SERIALIZE +#define HB_NO_BUFFER_VERIFY #define HB_NO_BITMAP #define HB_NO_CFF #define HB_NO_COLOR @@ -84,6 +85,7 @@ #ifdef HB_MINI #define HB_NO_AAT #define HB_NO_LEGACY +#define HB_NO_BORING_EXPANSION #endif #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H) diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc index a512f3b8b7..6ccc1b0a2b 100644 --- a/thirdparty/harfbuzz/src/hb-coretext.cc +++ b/thirdparty/harfbuzz/src/hb-coretext.cc @@ -481,8 +481,8 @@ struct active_feature_t { a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 0; } - bool operator== (const active_feature_t *f) { - return cmp (this, f) == 0; + bool operator== (const active_feature_t& f) const { + return cmp (this, &f) == 0; } }; @@ -677,7 +677,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, { active_features.push (event->feature); } else { - active_feature_t *feature = active_features.find (&event->feature); + active_feature_t *feature = active_features.lsearch (event->feature); if (feature) active_features.remove (feature - active_features.arrayZ); } @@ -897,7 +897,7 @@ resize_and_retry: DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs); buffer->len = 0; - uint32_t status_and = ~0, status_or = 0; + uint32_t status_or = 0; CGFloat advances_so_far = 0; /* For right-to-left runs, CoreText returns the glyphs positioned such that * any trailing whitespace is to the left of (0,0). Adjust coordinate system @@ -918,7 +918,6 @@ resize_and_retry: CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i)); CTRunStatus run_status = CTRunGetStatus (run); status_or |= run_status; - status_and &= run_status; DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr); if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) @@ -1140,21 +1139,6 @@ resize_and_retry: buffer->len += num_glyphs; } - /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel, - * or if it does, it doesn't respect it. So we get runs with wrong - * directions. As such, disable the assert... It wouldn't crash, but - * cursoring will be off... - * - * https://crbug.com/419769 - */ - if (false) - { - /* Make sure all runs had the expected direction. */ - HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); - assert (bool (status_and & kCTRunStatusRightToLeft) == backward); - assert (bool (status_or & kCTRunStatusRightToLeft) == backward); - } - buffer->clear_positions (); unsigned int count = buffer->len; @@ -1213,7 +1197,8 @@ resize_and_retry: } } - buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); #undef FAIL diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc index dea87b8cd0..f177ff31c0 100644 --- a/thirdparty/harfbuzz/src/hb-directwrite.cc +++ b/thirdparty/harfbuzz/src/hb-directwrite.cc @@ -762,7 +762,8 @@ retry_getglyphs: if (isRightToLeft) hb_buffer_reverse (buffer); - buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); delete [] clusterMap; delete [] glyphIndices; diff --git a/thirdparty/harfbuzz/src/hb-draw.cc b/thirdparty/harfbuzz/src/hb-draw.cc index c0af6ce013..b31019b07e 100644 --- a/thirdparty/harfbuzz/src/hb-draw.cc +++ b/thirdparty/harfbuzz/src/hb-draw.cc @@ -25,237 +25,313 @@ #include "hb.hh" #ifndef HB_NO_DRAW -#ifdef HB_EXPERIMENTAL_API #include "hb-draw.hh" -#include "hb-ot.h" -#include "hb-ot-glyf-table.hh" -#include "hb-ot-cff1-table.hh" -#include "hb-ot-cff2-table.hh" /** - * hb_draw_funcs_set_move_to_func: - * @funcs: draw functions object - * @move_to: move-to callback + * SECTION:hb-draw + * @title: hb-draw + * @short_description: Glyph drawing + * @include: hb.h * - * Sets move-to callback to the draw functions object. - * - * Since: EXPERIMENTAL + * Functions for drawing (extracting) glyph shapes. **/ -void -hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, - hb_draw_move_to_func_t move_to) + +static void +hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->move_to = move_to; + dfuncs->emit_cubic_to (draw_data, *st, + (st->current_x + 2.f * control_x) / 3.f, + (st->current_y + 2.f * control_y) / 3.f, + (to_x + 2.f * control_x) / 3.f, + (to_y + 2.f * control_y) / 3.f, + to_x, to_y); +} + +static void +hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float control1_x HB_UNUSED, float control1_y HB_UNUSED, + float control2_x HB_UNUSED, float control2_y HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + void *user_data HB_UNUSED) {} + + +#define HB_DRAW_FUNC_IMPLEMENT(name) \ + \ +void \ +hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ + hb_draw_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ +{ \ + if (hb_object_is_immutable (dfuncs)) \ + return; \ + \ + if (dfuncs->destroy.name) \ + dfuncs->destroy.name (dfuncs->user_data.name); \ + \ + if (func) { \ + dfuncs->func.name = func; \ + dfuncs->user_data.name = user_data; \ + dfuncs->destroy.name = destroy; \ + } else { \ + dfuncs->func.name = hb_draw_##name##_nil; \ + dfuncs->user_data.name = nullptr; \ + dfuncs->destroy.name = nullptr; \ + } \ } +HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + /** - * hb_draw_funcs_set_line_to_func: - * @funcs: draw functions object - * @line_to: line-to callback + * hb_draw_funcs_create: (Xconstructor) + * + * Creates a new draw callbacks object. * - * Sets line-to callback to the draw functions object. + * Return value: (transfer full): + * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial + * reference count should be released with hb_draw_funcs_destroy when you are + * done using the #hb_draw_funcs_t. This function never returns %NULL. If + * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will + * be returned. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -void -hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, - hb_draw_line_to_func_t line_to) +hb_draw_funcs_t * +hb_draw_funcs_create () { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->line_to = line_to; + hb_draw_funcs_t *dfuncs; + if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ()))) + return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); + + dfuncs->func = Null (hb_draw_funcs_t).func; + + return dfuncs; } +DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = +{ + HB_OBJECT_HEADER_STATIC, + + { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil, + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } +}; + + /** - * hb_draw_funcs_set_quadratic_to_func: - * @funcs: draw functions object - * @move_to: quadratic-to callback + * hb_draw_funcs_reference: (skip) + * @dfuncs: draw functions + * + * Increases the reference count on @dfuncs by one. This prevents @buffer from + * being destroyed until a matching call to hb_draw_funcs_destroy() is made. * - * Sets quadratic-to callback to the draw functions object. + * Return value: (transfer full): + * The referenced #hb_draw_funcs_t. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -void -hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, - hb_draw_quadratic_to_func_t quadratic_to) +hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->quadratic_to = quadratic_to; - funcs->is_quadratic_to_set = true; + return hb_object_reference (dfuncs); } /** - * hb_draw_funcs_set_cubic_to_func: - * @funcs: draw functions - * @cubic_to: cubic-to callback + * hb_draw_funcs_destroy: (skip) + * @dfuncs: draw functions * - * Sets cubic-to callback to the draw functions object. + * Deallocate the @dfuncs. + * Decreases the reference count on @dfuncs by one. If the result is zero, then + * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference(). * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, - hb_draw_cubic_to_func_t cubic_to) +hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->cubic_to = cubic_to; + if (!hb_object_destroy (dfuncs)) return; + +#define HB_DRAW_FUNC_IMPLEMENT(name) \ + if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name); + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + + + hb_free (dfuncs); } /** - * hb_draw_funcs_set_close_path_func: - * @funcs: draw functions object - * @close_path: close-path callback + * hb_draw_funcs_make_immutable: + * @dfuncs: draw functions * - * Sets close-path callback to the draw functions object. + * Makes @dfuncs object immutable. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, - hb_draw_close_path_func_t close_path) +hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->close_path = close_path; -} - -static void -_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} - -static void -_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} - -static void -_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED, - hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, - void *user_data HB_UNUSED) {} - -static void -_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED, - hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED, - hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, - void *user_data HB_UNUSED) {} + if (hb_object_is_immutable (dfuncs)) + return; -static void -_close_path_nil (void *user_data HB_UNUSED) {} + hb_object_make_immutable (dfuncs); +} /** - * hb_draw_funcs_create: + * hb_draw_funcs_is_immutable: + * @dfuncs: draw functions * - * Creates a new draw callbacks object. + * Checks whether @dfuncs is immutable. + * + * Return value: %true if @dfuncs is immutable, %false otherwise * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_draw_funcs_t * -hb_draw_funcs_create () +hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs) { - hb_draw_funcs_t *funcs; - if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ()))) - return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); - - funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil; - funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil; - funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil; - funcs->is_quadratic_to_set = false; - funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil; - funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil; - return funcs; + return hb_object_is_immutable (dfuncs); } + /** - * hb_draw_funcs_reference: - * @funcs: draw functions + * hb_draw_move_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point * - * Add to callbacks object refcount. + * Perform a "move-to" draw operation. * - * Returns: The same object. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_draw_funcs_t * -hb_draw_funcs_reference (hb_draw_funcs_t *funcs) +void +hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y) { - return hb_object_reference (funcs); + dfuncs->move_to (draw_data, *st, + to_x, to_y); } /** - * hb_draw_funcs_destroy: - * @funcs: draw functions + * hb_draw_line_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point * - * Decreases refcount of callbacks object and deletes the object if it reaches - * to zero. + * Perform a "line-to" draw operation. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_destroy (hb_draw_funcs_t *funcs) +hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y) { - if (!hb_object_destroy (funcs)) return; - - hb_free (funcs); + dfuncs->line_to (draw_data, *st, + to_x, to_y); } /** - * hb_draw_funcs_make_immutable: - * @funcs: draw functions + * hb_draw_quadratic_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @control_x: X component of control point + * @control_y: Y component of control point + * @to_x: X component of target point + * @to_y: Y component of target point * - * Makes funcs object immutable. + * Perform a "quadratic-to" draw operation. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs) +hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y) { - if (hb_object_is_immutable (funcs)) - return; - - hb_object_make_immutable (funcs); + dfuncs->quadratic_to (draw_data, *st, + control_x, control_y, + to_x, to_y); } /** - * hb_draw_funcs_is_immutable: - * @funcs: draw functions + * hb_draw_cubic_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @control1_x: X component of first control point + * @control1_y: Y component of first control point + * @control2_x: X component of second control point + * @control2_y: Y component of second control point + * @to_x: X component of target point + * @to_y: Y component of target point * - * Checks whether funcs is immutable. + * Perform a "cubic-to" draw operation. * - * Returns: If is immutable. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_bool_t -hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs) +void +hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) { - return hb_object_is_immutable (funcs); + dfuncs->cubic_to (draw_data, *st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y); } /** - * hb_font_draw_glyph: - * @font: a font object - * @glyph: a glyph id - * @funcs: draw callbacks object - * @user_data: parameter you like be passed to the callbacks when are called + * hb_draw_close_path: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state * - * Draw a glyph. + * Perform a "close-path" draw operation. * - * Returns: Whether the font had the glyph and the operation completed successfully. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_bool_t -hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, - const hb_draw_funcs_t *funcs, - void *user_data) +void +hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st) { - if (unlikely (funcs == &Null (hb_draw_funcs_t) || - glyph >= font->face->get_num_glyphs ())) - return false; - - draw_helper_t draw_helper (funcs, user_data); - if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true; -#ifndef HB_NO_CFF - if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true; - if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true; -#endif - - return false; + dfuncs->close_path (draw_data, *st); } -#endif + #endif diff --git a/thirdparty/harfbuzz/src/hb-draw.h b/thirdparty/harfbuzz/src/hb-draw.h index bddc876399..c45a53212a 100644 --- a/thirdparty/harfbuzz/src/hb-draw.h +++ b/thirdparty/harfbuzz/src/hb-draw.h @@ -33,65 +33,292 @@ HB_BEGIN_DECLS -#ifdef HB_EXPERIMENTAL_API -typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); -typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); -typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y, - hb_position_t to_x, hb_position_t to_y, - void *user_data); -typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y, - hb_position_t control2_x, hb_position_t control2_y, - hb_position_t to_x, hb_position_t to_y, - void *user_data); -typedef void (*hb_draw_close_path_func_t) (void *user_data); + +/** + * hb_draw_state_t + * @path_open: Whether there is an open path + * @path_start_x: X component of the start of current path + * @path_start_y: Y component of the start of current path + * @current_x: X component of current point + * @current_y: Y component of current point + * + * Current drawing state. + * + * Since: 4.0.0 + **/ +typedef struct hb_draw_state_t { + hb_bool_t path_open; + + float path_start_x; + float path_start_y; + + float current_x; + float current_y; + + /*< private >*/ + hb_var_num_t reserved1; + hb_var_num_t reserved2; + hb_var_num_t reserved3; + hb_var_num_t reserved4; + hb_var_num_t reserved5; + hb_var_num_t reserved6; + hb_var_num_t reserved7; +} hb_draw_state_t; + +/** + * HB_DRAW_STATE_DEFAULT: + * + * The default #hb_draw_state_t at the start of glyph drawing. + */ +#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}} + /** * hb_draw_funcs_t: * * Glyph draw callbacks. * - * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we - * translate _quadratic_to calls to _cubic_to if the callback isn't defined. + * #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and + * #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate + * #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the + * callback isn't defined. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ + typedef struct hb_draw_funcs_t hb_draw_funcs_t; + +/** + * hb_draw_move_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_line_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_quadratic_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @control_x: X component of control point + * @control_y: Y component of control point + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_cubic_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @control1_x: X component of first control point + * @control1_y: Y component of first control point + * @control2_x: X component of second control point + * @control2_y: Y component of second control point + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_close_path_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + void *user_data); + +/** + * hb_draw_funcs_set_move_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): move-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets move-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, - hb_draw_move_to_func_t move_to); +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_move_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_line_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): line-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets line-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, - hb_draw_line_to_func_t line_to); +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_line_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_quadratic_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets quadratic-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, - hb_draw_quadratic_to_func_t quadratic_to); +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_quadratic_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_cubic_to_func: + * @dfuncs: draw functions + * @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets cubic-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, - hb_draw_cubic_to_func_t cubic_to); +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_cubic_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_close_path_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): close-path callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets close-path callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, - hb_draw_close_path_func_t close_path); +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, + hb_draw_close_path_func_t func, + void *user_data, hb_destroy_func_t destroy); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); HB_EXTERN hb_draw_funcs_t * -hb_draw_funcs_reference (hb_draw_funcs_t *funcs); +hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); HB_EXTERN void -hb_draw_funcs_destroy (hb_draw_funcs_t *funcs); +hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); HB_EXTERN void -hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs); +hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); HB_EXTERN hb_bool_t -hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs); -#endif +hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs); + + +HB_EXTERN void +hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st); + HB_END_DECLS diff --git a/thirdparty/harfbuzz/src/hb-draw.hh b/thirdparty/harfbuzz/src/hb-draw.hh index 2aa0a5b4db..28bc9218e1 100644 --- a/thirdparty/harfbuzz/src/hb-draw.hh +++ b/thirdparty/harfbuzz/src/hb-draw.hh @@ -27,113 +27,205 @@ #include "hb.hh" -#ifdef HB_EXPERIMENTAL_API -struct hb_draw_funcs_t -{ - hb_object_header_t header; - hb_draw_move_to_func_t move_to; - hb_draw_line_to_func_t line_to; - hb_draw_quadratic_to_func_t quadratic_to; - bool is_quadratic_to_set; - hb_draw_cubic_to_func_t cubic_to; - hb_draw_close_path_func_t close_path; -}; +/* + * hb_draw_funcs_t + */ + +#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \ + HB_DRAW_FUNC_IMPLEMENT (move_to) \ + HB_DRAW_FUNC_IMPLEMENT (line_to) \ + HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \ + HB_DRAW_FUNC_IMPLEMENT (cubic_to) \ + HB_DRAW_FUNC_IMPLEMENT (close_path) \ + /* ^--- Add new callbacks here */ -struct draw_helper_t +struct hb_draw_funcs_t { - draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_) - { - funcs = funcs_; - user_data = user_data_; - path_open = false; - path_start_x = current_x = path_start_y = current_y = 0; - } - ~draw_helper_t () { end_path (); } + hb_object_header_t header; - void move_to (hb_position_t x, hb_position_t y) + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } func; + + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) void *name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } user_data; + + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } destroy; + + void emit_move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) + { func.move_to (this, draw_data, &st, + to_x, to_y, + user_data.move_to); } + void emit_line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) + { func.line_to (this, draw_data, &st, + to_x, to_y, + user_data.line_to); } + void emit_quadratic_to (void *draw_data, hb_draw_state_t &st, + float control_x, float control_y, + float to_x, float to_y) + { func.quadratic_to (this, draw_data, &st, + control_x, control_y, + to_x, to_y, + user_data.quadratic_to); } + void emit_cubic_to (void *draw_data, hb_draw_state_t &st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) + { func.cubic_to (this, draw_data, &st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y, + user_data.cubic_to); } + void emit_close_path (void *draw_data, hb_draw_state_t &st) + { func.close_path (this, draw_data, &st, + user_data.close_path); } + + + void move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (path_open) end_path (); - current_x = path_start_x = x; - current_y = path_start_y = y; + if (st.path_open) close_path (draw_data, st); + st.current_x = to_x; + st.current_y = to_y; } - void line_to (hb_position_t x, hb_position_t y) + void line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (equal_to_current (x, y)) return; - if (!path_open) start_path (); - funcs->line_to (x, y, user_data); - current_x = x; - current_y = y; + if (!st.path_open) start_path (draw_data, st); + emit_line_to (draw_data, st, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } void - quadratic_to (hb_position_t control_x, hb_position_t control_y, - hb_position_t to_x, hb_position_t to_y) + quadratic_to (void *draw_data, hb_draw_state_t &st, + float control_x, float control_y, + float to_x, float to_y) { - if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y)) - return; - if (!path_open) start_path (); - if (funcs->is_quadratic_to_set) - funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data); - else - funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f), - roundf ((current_y + 2.f * control_y) / 3.f), - roundf ((to_x + 2.f * control_x) / 3.f), - roundf ((to_y + 2.f * control_y) / 3.f), - to_x, to_y, user_data); - current_x = to_x; - current_y = to_y; + if (!st.path_open) start_path (draw_data, st); + emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } void - cubic_to (hb_position_t control1_x, hb_position_t control1_y, - hb_position_t control2_x, hb_position_t control2_y, - hb_position_t to_x, hb_position_t to_y) + cubic_to (void *draw_data, hb_draw_state_t &st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) { - if (equal_to_current (control1_x, control1_y) && - equal_to_current (control2_x, control2_y) && - equal_to_current (to_x, to_y)) - return; - if (!path_open) start_path (); - funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data); - current_x = to_x; - current_y = to_y; + if (!st.path_open) start_path (draw_data, st); + emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } - void end_path () + void + close_path (void *draw_data, hb_draw_state_t &st) { - if (path_open) + if (st.path_open) { - if ((path_start_x != current_x) || (path_start_y != current_y)) - funcs->line_to (path_start_x, path_start_y, user_data); - funcs->close_path (user_data); + if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) + emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); + emit_close_path (draw_data, st); } - path_open = false; - path_start_x = current_x = path_start_y = current_y = 0; + st.path_open = false; + st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0; } protected: - bool equal_to_current (hb_position_t x, hb_position_t y) - { return current_x == x && current_y == y; } - void start_path () + void start_path (void *draw_data, hb_draw_state_t &st) { - if (path_open) end_path (); - path_open = true; - funcs->move_to (path_start_x, path_start_y, user_data); + assert (!st.path_open); + emit_move_to (draw_data, st, st.current_x, st.current_y); + st.path_open = true; + st.path_start_x = st.current_x; + st.path_start_y = st.current_y; } +}; +DECLARE_NULL_INSTANCE (hb_draw_funcs_t); - hb_position_t path_start_x; - hb_position_t path_start_y; +struct hb_draw_session_t +{ + hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) + : slant {slant_}, not_slanted {slant == 0.f}, + funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT + {} - hb_position_t current_x; - hb_position_t current_y; + ~hb_draw_session_t () { close_path (); } - bool path_open; - const hb_draw_funcs_t *funcs; - void *user_data; + void move_to (float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->move_to (draw_data, st, + to_x, to_y); + else + funcs->move_to (draw_data, st, + to_x + to_y * slant, to_y); + } + void line_to (float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->line_to (draw_data, st, + to_x, to_y); + else + funcs->line_to (draw_data, st, + to_x + to_y * slant, to_y); + } + void + quadratic_to (float control_x, float control_y, + float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->quadratic_to (draw_data, st, + control_x, control_y, + to_x, to_y); + else + funcs->quadratic_to (draw_data, st, + control_x + control_y * slant, control_y, + to_x + to_y * slant, to_y); + } + void + cubic_to (float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->cubic_to (draw_data, st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y); + else + funcs->cubic_to (draw_data, st, + control1_x + control1_y * slant, control1_y, + control2_x + control2_y * slant, control2_y, + to_x + to_y * slant, to_y); + } + void close_path () + { + funcs->close_path (draw_data, st); + } + + protected: + float slant; + bool not_slanted; + hb_draw_funcs_t *funcs; + void *draw_data; + hb_draw_state_t st; }; -#endif #endif /* HB_DRAW_HH */ diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc index 2c0087370c..5365598636 100644 --- a/thirdparty/harfbuzz/src/hb-face.cc +++ b/thirdparty/harfbuzz/src/hb-face.cc @@ -143,7 +143,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, typedef struct hb_face_for_data_closure_t { hb_blob_t *blob; - unsigned int index; + uint16_t index; } hb_face_for_data_closure_t; static hb_face_for_data_closure_t * @@ -156,7 +156,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) return nullptr; closure->blob = blob; - closure->index = index; + closure->index = (uint16_t) (index & 0xFFFFu); return closure; } @@ -195,9 +195,19 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * @index: The index of the face within @blob * * Constructs a new face object from the specified blob and - * a face index into that blob. This is used for blobs of - * file formats such as Dfont and TTC that can contain more - * than one face. + * a face index into that blob. + * + * The face index is used for blobs of file formats such as TTC and + * and DFont that can contain more than one face. Face indices within + * such collections are zero-based. + * + * <note>Note: If the blob font format is not a collection, @index + * is ignored. Otherwise, only the lower 16-bits of @index are used. + * The unmodified @index can be accessed via hb_face_get_index().</note> + * + * <note>Note: The high 16-bits of @index, if non-zero, are used by + * hb_font_create() to load named-instances in variable fonts. See + * hb_font_create() for details.</note> * * Return value: (transfer full): The new face object * @@ -420,7 +430,8 @@ hb_face_reference_blob (hb_face_t *face) * Assigns the specified face-index to @face. Fails if the * face is immutable. * - * <note>Note: face indices within a collection are zero-based.</note> + * <note>Note: changing the index has no effect on the face itself + * This only changes the value returned by hb_face_get_index().</note> * * Since: 0.9.2 **/ diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc index fa8da96395..5700e06271 100644 --- a/thirdparty/harfbuzz/src/hb-font.cc +++ b/thirdparty/harfbuzz/src/hb-font.cc @@ -29,6 +29,7 @@ #include "hb.hh" #include "hb-font.hh" +#include "hb-draw.hh" #include "hb-machinery.hh" #include "hb-ot.h" @@ -501,6 +502,136 @@ hb_font_get_glyph_from_name_default (hb_font_t *font, return font->parent->get_glyph_from_name (name, len, glyph); } +static void +hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) +{ +} + + +typedef struct hb_font_get_glyph_shape_default_adaptor_t { + hb_draw_funcs_t *draw_funcs; + void *draw_data; + float x_scale; + float y_scale; +} hb_font_get_glyph_shape_default_adaptor_t; + +static void +hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, + x_scale * control_x, y_scale * control_y, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, + x_scale * control1_x, y_scale * control1_y, + x_scale * control2_x, y_scale * control2_y, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + + adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); +} + +static const hb_draw_funcs_t _hb_draw_funcs_default = { + HB_OBJECT_HEADER_STATIC, + + { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default, + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } +}; + +static void +hb_font_get_glyph_shape_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t adaptor = { + draw_funcs, + draw_data, + (float) font->x_scale / (float) font->parent->x_scale, + (float) font->y_scale / (float) font->parent->y_scale + }; + + font->parent->get_glyph_shape (glyph, + const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default), + &adaptor); +} + DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, @@ -631,7 +762,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the specified font-functions structure. + * Attaches a user-data key/data pair to the specified font-functions structure. * * Return value: %true if success, %false otherwise * @@ -821,7 +952,7 @@ hb_font_get_glyph (hb_font_t *font, * @glyph: (out): The glyph ID retrieved * * Fetches the nominal glyph ID for a Unicode code point in the - * specified font. + * specified font. * * This version of the function should not be used to fetch glyph IDs * for code points modified by variation selectors. For variation-selector @@ -940,7 +1071,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font, * @advance_stride: The stride between successive advances * * Fetches the advances for a sequence of glyph IDs in the specified - * font, for horizontal text segments. + * font, for horizontal text segments. * * Since: 1.8.6 **/ @@ -964,7 +1095,7 @@ hb_font_get_glyph_h_advances (hb_font_t* font, * @advance_stride: (out): The stride between successive advances * * Fetches the advances for a sequence of glyph IDs in the specified - * font, for vertical text segments. + * font, for vertical text segments. * * Since: 1.8.6 **/ @@ -1168,6 +1299,26 @@ hb_font_get_glyph_from_name (hb_font_t *font, return font->get_glyph_from_name (name, len, glyph); } +/** + * hb_font_get_glyph_shape: + * @font: #hb_font_t to work upon + * @glyph: : The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Fetches the glyph shape that corresponds to a glyph in the specified @font. + * The shape is returned by way of calls to the callsbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Since: 4.0.0 + **/ +void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + font->get_glyph_shape (glyph, dfuncs, draw_data); +} /* A bit higher-level, and with fallback */ @@ -1190,7 +1341,7 @@ hb_font_get_extents_for_direction (hb_font_t *font, hb_direction_t direction, hb_font_extents_t *extents) { - return font->get_extents_for_direction (direction, extents); + font->get_extents_for_direction (direction, extents); } /** * hb_font_get_glyph_advance_for_direction: @@ -1215,7 +1366,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, hb_position_t *x, hb_position_t *y) { - return font->get_glyph_advance_for_direction (glyph, direction, x, y); + font->get_glyph_advance_for_direction (glyph, direction, x, y); } /** * hb_font_get_glyph_advances_for_direction: @@ -1278,7 +1429,7 @@ hb_font_get_glyph_origin_for_direction (hb_font_t *font, * @font: #hb_font_t to work upon * @glyph: The glyph ID to query * @direction: The direction of the text segment - * @x: (inout): Input = The original X coordinate + * @x: (inout): Input = The original X coordinate * Output = The X coordinate plus the X-coordinate of the origin * @y: (inout): Input = The original Y coordinate * Output = The Y coordinate plus the Y-coordinate of the origin @@ -1306,7 +1457,7 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font, * @font: #hb_font_t to work upon * @glyph: The glyph ID to query * @direction: The direction of the text segment - * @x: (inout): Input = The original X coordinate + * @x: (inout): Input = The original X coordinate * Output = The X coordinate minus the X-coordinate of the origin * @y: (inout): Input = The original Y coordinate * Output = The Y coordinate minus the Y-coordinate of the origin @@ -1477,6 +1628,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ + 0., /* slant */ + 0., /* slant_xy; */ 1<<16, /* x_mult */ 1<<16, /* y_mult */ @@ -1521,6 +1674,13 @@ _hb_font_create (hb_face_t *face) * * Constructs a new font object from the specified face. * + * <note>Note: If @face's index value (as passed to hb_face_create() + * has non-zero top 16-bits, those bits minus one are passed to + * hb_font_set_var_named_instance(), effectively loading a named-instance + * of a variable font, instead of the default-instance. This allows + * specifying which named-instance to load by default when creating the + * face.</note> + * * Return value: (transfer full): The new font object * * Since: 0.9.2 @@ -1535,6 +1695,11 @@ hb_font_create (hb_face_t *face) hb_ot_font_set_funcs (font); #endif +#ifndef HB_NO_VAR + if (face && face->index >> 16) + hb_font_set_var_named_instance (font, (face->index >> 16) - 1); +#endif + return font; } @@ -1578,6 +1743,7 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->slant = parent->slant; font->mults_changed (); font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -1668,12 +1834,12 @@ hb_font_destroy (hb_font_t *font) /** * hb_font_set_user_data: (skip) * @font: #hb_font_t to work upon - * @key: The user-data key + * @key: The user-data key * @data: A pointer to the user data * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the specified font object. + * Attaches a user-data key/data pair to the specified font object. * * Return value: %true if success, %false otherwise * @@ -1875,7 +2041,7 @@ hb_font_set_funcs (hb_font_t *font, * @font_data: (destroy destroy) (scope notified): Data to attach to @font * @destroy: (nullable): The function to call when @font_data is not needed anymore * - * Replaces the user data attached to a font, updating the font's + * Replaces the user data attached to a font, updating the font's * @destroy callback. * * Since: 0.9.2 @@ -1949,7 +2115,7 @@ hb_font_get_scale (hb_font_t *font, * @x_ppem: Horizontal ppem value to assign * @y_ppem: Vertical ppem value to assign * - * Sets the horizontal and vertical pixels-per-em (ppem) of a font. + * Sets the horizontal and vertical pixels-per-em (ppem) of a font. * * Since: 0.9.2 **/ @@ -1971,7 +2137,7 @@ hb_font_set_ppem (hb_font_t *font, * @x_ppem: (out): Horizontal ppem value * @y_ppem: (out): Vertical ppem value * - * Fetches the horizontal and vertical points-per-em (ppem) of a font. + * Fetches the horizontal and vertical points-per-em (ppem) of a font. * * Since: 0.9.2 **/ @@ -2015,7 +2181,7 @@ hb_font_set_ptem (hb_font_t *font, * * Return value: Point size. A value of zero means "not set." * - * Since: 0.9.2 + * Since: 1.6.0 **/ float hb_font_get_ptem (hb_font_t *font) @@ -2023,6 +2189,53 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +/** + * hb_font_set_synthetic_slant: + * @font: #hb_font_t to work upon + * @slant: synthetic slant value. + * + * Sets the "synthetic slant" of a font. By default is zero. + * Synthetic slant is the graphical skew applied to the font + * at rendering time. + * + * HarfBuzz needs to know this value to adjust shaping results, + * metrics, and style values to match the slanted rendering. + * + * <note>Note: The glyph shape fetched via the + * hb_font_get_glyph_shape() is slanted to reflect this value + * as well.</note> + * + * <note>Note: The slant value is a ratio. For example, a + * 20% slant would be represented as a 0.2 value.</note> + * + * Since: 3.3.0 + **/ +HB_EXTERN void +hb_font_set_synthetic_slant (hb_font_t *font, float slant) +{ + if (hb_object_is_immutable (font)) + return; + + font->slant = slant; + font->mults_changed (); +} + +/** + * hb_font_get_synthetic_slant: + * @font: #hb_font_t to work upon + * + * Fetches the "synthetic slant" of a font. + * + * Return value: Synthetic slant. By default is zero. + * + * Since: 3.3.0 + **/ +HB_EXTERN float +hb_font_get_synthetic_slant (hb_font_t *font) +{ + return font->slant; +} + #ifndef HB_NO_VAR /* * Variations @@ -2036,6 +2249,10 @@ hb_font_get_ptem (hb_font_t *font) * * Applies a list of font-variation settings to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @variations will be effectively set to their + * default values. + * * Since: 1.4.2 */ void @@ -2091,6 +2308,10 @@ hb_font_set_variations (hb_font_t *font, * Applies a list of variation coordinates (in design-space units) * to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @coords will be effectively set to their + * default values. + * * Since: 1.4.2 */ void @@ -2154,6 +2375,10 @@ hb_font_set_var_named_instance (hb_font_t *font, * Applies a list of variation coordinates (in normalized units) * to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @coords will be effectively set to their + * default values. + * * <note>Note: Coordinates should be normalized to 2.14.</note> * * Since: 1.4.2 @@ -2196,14 +2421,19 @@ hb_font_set_var_coords_normalized (hb_font_t *font, /** * hb_font_get_var_coords_normalized: * @font: #hb_font_t to work upon - * @length: Number of coordinates retrieved + * @length: (out): Number of coordinates retrieved * * Fetches the list of normalized variation coordinates currently * set on a font. * + * Note that this returned array may only contain values for some + * (or none) of the axes; omitted axes effectively have zero values. + * * Return value is valid as long as variation coordinates of the font * are not modified. * + * Return value: coordinates array + * * Since: 1.4.2 */ const int * @@ -2216,18 +2446,24 @@ hb_font_get_var_coords_normalized (hb_font_t *font, return font->coords; } -#ifdef HB_EXPERIMENTAL_API /** * hb_font_get_var_coords_design: * @font: #hb_font_t to work upon - * @length: (out): number of coordinates + * @length: (out): Number of coordinates retrieved + * + * Fetches the list of variation coordinates (in design-space units) currently + * set on a font. + * + * Note that this returned array may only contain values for some + * (or none) of the axes; omitted axes effectively have their default + * values. * * Return value is valid as long as variation coordinates of the font * are not modified. * * Return value: coordinates array * - * Since: EXPERIMENTAL + * Since: 3.3.0 */ const float * hb_font_get_var_coords_design (hb_font_t *font, @@ -2239,7 +2475,6 @@ hb_font_get_var_coords_design (hb_font_t *font, return font->design_coords; } #endif -#endif #ifndef HB_DISABLE_DEPRECATED /* @@ -2361,12 +2596,14 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, return; } + /* Since we pass it to two destroying functions. */ + trampoline_reference (&trampoline->closure); + hb_font_funcs_set_nominal_glyph_func (ffuncs, hb_font_get_nominal_glyph_trampoline, trampoline, trampoline_destroy); - trampoline_reference (&trampoline->closure); hb_font_funcs_set_variation_glyph_func (ffuncs, hb_font_get_variation_glyph_trampoline, trampoline, diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h index 15dc126523..9548857535 100644 --- a/thirdparty/harfbuzz/src/hb-font.h +++ b/thirdparty/harfbuzz/src/hb-font.h @@ -511,6 +511,25 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * hb_codepoint_t *glyph, void *user_data); +/** + * hb_font_get_glyph_shape_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + /* func setters */ @@ -770,6 +789,22 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_from_name_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_glyph_shape_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_shape_func_t. + * + * Since: 4.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, hb_destroy_func_t destroy); + /* func dispatch */ HB_EXTERN hb_bool_t @@ -850,6 +885,11 @@ hb_font_get_glyph_from_name (hb_font_t *font, const char *name, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph); +HB_EXTERN void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + /* high-level funcs, with fallback */ @@ -1024,6 +1064,12 @@ HB_EXTERN float hb_font_get_ptem (hb_font_t *font); HB_EXTERN void +hb_font_set_synthetic_slant (hb_font_t *font, float slant); + +HB_EXTERN float +hb_font_get_synthetic_slant (hb_font_t *font); + +HB_EXTERN void hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length); @@ -1033,11 +1079,9 @@ hb_font_set_var_coords_design (hb_font_t *font, const float *coords, unsigned int coords_length); -#ifdef HB_EXPERIMENTAL_API HB_EXTERN const float * hb_font_get_var_coords_design (hb_font_t *font, unsigned int *length); -#endif HB_EXTERN void hb_font_set_var_coords_normalized (hb_font_t *font, @@ -1052,11 +1096,6 @@ HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, unsigned instance_index); -#ifdef HB_EXPERIMENTAL_API -HB_EXTERN hb_bool_t -hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, - const hb_draw_funcs_t *funcs, void *user_data); -#endif HB_END_DECLS diff --git a/thirdparty/harfbuzz/src/hb-font.hh b/thirdparty/harfbuzz/src/hb-font.hh index 1b7f445e8b..70311b4a85 100644 --- a/thirdparty/harfbuzz/src/hb-font.hh +++ b/thirdparty/harfbuzz/src/hb-font.hh @@ -57,6 +57,7 @@ HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ HB_FONT_FUNC_IMPLEMENT (glyph_name) \ HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ + HB_FONT_FUNC_IMPLEMENT (glyph_shape) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -109,6 +110,8 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + float slant; + float slant_xy; int64_t x_mult; int64_t y_mult; @@ -138,6 +141,8 @@ struct hb_font_t hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); } float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } + float em_fscalef_x (float v) { return em_fscalef (v, x_scale); } + float em_fscalef_y (float v) { return em_fscalef (v, y_scale); } hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) { return em_mult (v, dir_mult (direction)); } @@ -371,6 +376,15 @@ struct hb_font_t klass->user_data.glyph_from_name); } + void get_glyph_shape (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data) + { + klass->get.f.glyph_shape (this, user_data, + glyph, + draw_funcs, draw_data, + klass->user_data.glyph_shape); + } + /* A bit higher-level, and with fallback */ @@ -617,12 +631,15 @@ struct hb_font_t signed upem = face->get_upem (); x_mult = ((int64_t) x_scale << 16) / upem; y_mult = ((int64_t) y_scale << 16) / upem; + slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; } hb_position_t em_mult (int16_t v, int64_t mult) { return (hb_position_t) ((v * mult + 32768) >> 16); } hb_position_t em_scalef (float v, int scale) - { return (hb_position_t) roundf (v * scale / face->get_upem ()); } + { return (hb_position_t) roundf (em_fscalef (v, scale)); } + float em_fscalef (float v, int scale) + { return v * scale / face->get_upem (); } float em_fscale (int16_t v, int scale) { return (float) v * scale / face->get_upem (); } }; diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc index 67691e3ff3..d3c5d3db93 100644 --- a/thirdparty/harfbuzz/src/hb-ft.cc +++ b/thirdparty/harfbuzz/src/hb-ft.cc @@ -33,12 +33,14 @@ #include "hb-ft.h" +#include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-cache.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H +#include FT_OUTLINE_H #include FT_TRUETYPE_TABLES_H @@ -78,12 +80,12 @@ struct hb_ft_font_t { - mutable hb_mutex_t lock; - FT_Face ft_face; int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + mutable hb_mutex_t lock; + FT_Face ft_face; mutable int cached_x_scale; mutable hb_advance_cache_t advance_cache; }; @@ -380,6 +382,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ + return (-v + (1<<9)) >> 10; } #endif @@ -565,6 +568,82 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, return true; } +#ifndef HB_NO_DRAW + +static int +_hb_ft_move_to (const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->move_to (to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_line_to (const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->line_to (to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_conic_to (const FT_Vector *control, + const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->quadratic_to (control->x, control->y, + to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_cubic_to (const FT_Vector *control1, + const FT_Vector *control2, + const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->cubic_to (control1->x, control1->y, + control2->x, control2->y, + to->x, to->y); + return FT_Err_Ok; +} + +static void +hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, + FT_LOAD_NO_BITMAP | ft_font->load_flags))) + return; + + if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + return; + + const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc) _hb_ft_move_to, + (FT_Outline_LineToFunc) _hb_ft_line_to, + (FT_Outline_ConicToFunc) _hb_ft_conic_to, + (FT_Outline_CubicToFunc) _hb_ft_cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + + hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + + FT_Outline_Decompose (&ft_face->glyph->outline, + &outline_funcs, + &draw_session); +} +#endif + + static inline void free_static_ft_funcs (); static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t> @@ -596,6 +675,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr); hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr); +#ifndef HB_NO_DRAW + hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr); +#endif + hb_font_funcs_make_immutable (funcs); hb_atexit (free_static_ft_funcs); diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.cc b/thirdparty/harfbuzz/src/hb-gobject-structs.cc index 540b11f911..ef13f1e966 100644 --- a/thirdparty/harfbuzz/src/hb-gobject-structs.cc +++ b/thirdparty/harfbuzz/src/hb-gobject-structs.cc @@ -90,6 +90,7 @@ hb_gobject_##name##_get_type () \ HB_DEFINE_OBJECT_TYPE (buffer) HB_DEFINE_OBJECT_TYPE (blob) +HB_DEFINE_OBJECT_TYPE (draw_funcs) HB_DEFINE_OBJECT_TYPE (face) HB_DEFINE_OBJECT_TYPE (font) HB_DEFINE_OBJECT_TYPE (font_funcs) diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.h b/thirdparty/harfbuzz/src/hb-gobject-structs.h index 63467f80df..3914a2431a 100644 --- a/thirdparty/harfbuzz/src/hb-gobject-structs.h +++ b/thirdparty/harfbuzz/src/hb-gobject-structs.h @@ -49,6 +49,10 @@ hb_gobject_buffer_get_type (void); #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ()) HB_EXTERN GType +hb_gobject_draw_funcs_get_type (void); +#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ()) + +HB_EXTERN GType hb_gobject_face_get_type (void); #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc index 42420ac0b0..63dc18b466 100644 --- a/thirdparty/harfbuzz/src/hb-graphite2.cc +++ b/thirdparty/harfbuzz/src/hb-graphite2.cc @@ -439,7 +439,8 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, if (feats) gr_featureval_destroy (feats); gr_seg_destroy (seg); - buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); return true; } diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh index ad2e45e3c5..43a3098f65 100644 --- a/thirdparty/harfbuzz/src/hb-iter.hh +++ b/thirdparty/harfbuzz/src/hb-iter.hh @@ -90,8 +90,8 @@ struct hb_iter_t * it will be returning pointer to temporary rvalue. * TODO Use a wrapper return type to fix for non-reference type. */ template <typename T = item_t, - hb_enable_if (hb_is_reference (T))> - hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); } + hb_enable_if (std::is_reference<T>::value)> + hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); } item_t operator * () const { return thiz()->__item__ (); } item_t operator * () { return thiz()->__item__ (); } item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); } @@ -289,7 +289,7 @@ struct hb_is_source_of { private: template <typename Iter2 = Iter, - hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))> + hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<const Item>))> static hb_true_type impl (hb_priority<2>); template <typename Iter2 = Iter> static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ()); diff --git a/thirdparty/harfbuzz/src/hb-kern.hh b/thirdparty/harfbuzz/src/hb-kern.hh index 3f952fe7fc..9ea945caed 100644 --- a/thirdparty/harfbuzz/src/hb-kern.hh +++ b/thirdparty/harfbuzz/src/hb-kern.hh @@ -49,6 +49,10 @@ struct hb_kern_machine_t hb_mask_t kern_mask, bool scale = true) const { + if (!buffer->message (font, "start kern")) + return; + + buffer->unsafe_to_concat (); OT::hb_ot_apply_context_t c (1, font, buffer); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); @@ -67,7 +71,8 @@ struct hb_kern_machine_t } skippy_iter.reset (idx, 1); - if (!skippy_iter.next ()) + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) { idx++; continue; @@ -125,6 +130,8 @@ struct hb_kern_machine_t skip: idx = skippy_iter.idx; } + + (void) buffer->message (font, "end kern"); } const Driver &driver; diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh index 010c2570d7..e52a6a4124 100644 --- a/thirdparty/harfbuzz/src/hb-machinery.hh +++ b/thirdparty/harfbuzz/src/hb-machinery.hh @@ -194,7 +194,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> } const Returned * operator -> () const { return get (); } - const Returned & operator * () const { return *get (); } + template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))> + const U & operator * () const { return *get (); } explicit operator bool () const { return get_stored () != Funcs::get_null (); } template <typename C> operator const C * () const { return get (); } @@ -244,19 +245,19 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> { Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); if (likely (p)) - p->init (data); + p = new (p) Stored (data); return p; } static Stored *create () { Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); if (likely (p)) - p->init (); + p = new (p) Stored (); return p; } static void destroy (Stored *p) { - p->fini (); + p->~Stored (); hb_free (p); } @@ -272,14 +273,19 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, hb_face_lazy_loader_t<T, WheresFace>, hb_face_t, WheresFace> {}; -template <typename T, unsigned int WheresFace> +template <typename T, unsigned int WheresFace, bool core=false> struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, - hb_table_lazy_loader_t<T, WheresFace>, + hb_table_lazy_loader_t<T, WheresFace, core>, hb_face_t, WheresFace, hb_blob_t> { static hb_blob_t *create (hb_face_t *face) - { return hb_sanitize_context_t ().reference_table<T> (face); } + { + auto c = hb_sanitize_context_t (); + if (core) + c.set_num_glyphs (0); // So we don't recurse ad infinitum... + return c.reference_table<T> (face); + } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } static const hb_blob_t *get_null () diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc index 9f1ac42846..6c83c670c9 100644 --- a/thirdparty/harfbuzz/src/hb-map.cc +++ b/thirdparty/harfbuzz/src/hb-map.cc @@ -289,3 +289,23 @@ hb_map_get_population (const hb_map_t *map) { return map->get_population (); } + +/** + * hb_map_is_equal: + * @map: A map + * @other: Another map + * + * Tests whether @map and @other are equal (contain the same + * elements). + * + * Return value: %true if the two maps are equal, %false otherwise. + * + * Since: 4.3.0 + **/ +hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other) +{ + return map->is_equal (*other); +} + diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h index 6a45a7bdd5..3f67c50b92 100644 --- a/thirdparty/harfbuzz/src/hb-map.h +++ b/thirdparty/harfbuzz/src/hb-map.h @@ -91,6 +91,10 @@ hb_map_is_empty (const hb_map_t *map); HB_EXTERN unsigned int hb_map_get_population (const hb_map_t *map); +HB_EXTERN hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other); + HB_EXTERN void hb_map_set (hb_map_t *map, hb_codepoint_t key, diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh index 793dcf22ca..aec7d87f42 100644 --- a/thirdparty/harfbuzz/src/hb-map.hh +++ b/thirdparty/harfbuzz/src/hb-map.hh @@ -37,19 +37,17 @@ template <typename K, typename V, typename k_invalid_t = K, typename v_invalid_t = V, - k_invalid_t kINVALID = hb_is_pointer (K) ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1, - v_invalid_t vINVALID = hb_is_pointer (V) ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1> + k_invalid_t kINVALID = std::is_pointer<K>::value ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1, + v_invalid_t vINVALID = std::is_pointer<V>::value ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1> struct hb_hashmap_t { - static constexpr K INVALID_KEY = kINVALID; - static constexpr V INVALID_VALUE = vINVALID; - hb_hashmap_t () { init (); } + hb_hashmap_t (std::nullptr_t) : hb_hashmap_t () {} ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { hb_copy (o, *this); } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); } hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t () @@ -61,27 +59,46 @@ struct hb_hashmap_t hb_requires (hb_is_iterable (Iterable))> hb_hashmap_t (const Iterable &o) : hb_hashmap_t () { - hb_copy (o, *this); + auto iter = hb_iter (o); + if (iter.is_random_access_iterator) + resize (hb_len (iter)); + hb_copy (iter, *this); } - static_assert (std::is_trivially_copyable<K>::value, ""); - static_assert (std::is_trivially_copyable<V>::value, ""); - static_assert (std::is_trivially_destructible<K>::value, ""); - static_assert (std::is_trivially_destructible<V>::value, ""); - struct item_t { K key; V value; uint32_t hash; - void clear () { key = kINVALID; value = vINVALID; hash = 0; } + void clear () + { + new (std::addressof (key)) K (); + key = hb_coerce<K> (kINVALID); + new (std::addressof (value)) V (); + value = hb_coerce<V> (vINVALID); + hash = 0; + } bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } bool operator == (const item_t &o) { return *this == o.key; } - bool is_unused () const { return key == kINVALID; } - bool is_tombstone () const { return key != kINVALID && value == vINVALID; } - bool is_real () const { return key != kINVALID && value != vINVALID; } + bool is_unused () const + { + const K inv = hb_coerce<K> (kINVALID); + return key == inv; + } + bool is_tombstone () const + { + const K kinv = hb_coerce<K> (kINVALID); + const V vinv = hb_coerce<V> (vINVALID); + return key != kinv && value == vinv; + } + bool is_real () const + { + const K kinv = hb_coerce<K> (kINVALID); + const V vinv = hb_coerce<V> (vINVALID); + return key != kinv && value != vinv; + } hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } }; @@ -118,8 +135,13 @@ struct hb_hashmap_t } void fini_shallow () { - hb_free (items); - items = nullptr; + if (likely (items)) { + unsigned size = mask + 1; + for (unsigned i = 0; i < size; i++) + items[i].~item_t (); + hb_free (items); + items = nullptr; + } population = occupancy = 0; } void fini () @@ -136,11 +158,11 @@ struct hb_hashmap_t bool in_error () const { return !successful; } - bool resize () + bool resize (unsigned new_population = 0) { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (population * 2 + 8); + unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -163,10 +185,15 @@ struct hb_hashmap_t /* Insert back old items. */ if (old_items) for (unsigned int i = 0; i < old_size; i++) + { if (old_items[i].is_real ()) + { set_with_hash (old_items[i].key, old_items[i].hash, std::move (old_items[i].value)); + } + old_items[i].~item_t (); + } hb_free (old_items); @@ -178,22 +205,22 @@ struct hb_hashmap_t V get (K key) const { - if (unlikely (!items)) return vINVALID; + if (unlikely (!items)) return hb_coerce<V> (vINVALID); unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : vINVALID; + return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID); } - void del (K key) { set (key, vINVALID); } + void del (K key) { set (key, hb_coerce<V> (vINVALID)); } /* Has interface. */ - static constexpr V SENTINEL = vINVALID; typedef V value_t; value_t operator [] (K k) const { return get (k); } bool has (K k, V *vp = nullptr) const { V v = (*this)[k]; if (vp) *vp = v; - return v != SENTINEL; + const V vinv = hb_coerce<V> (vINVALID); + return v != vinv; } /* Projection. */ V operator () (K k) const { return get (k); } @@ -212,6 +239,27 @@ struct hb_hashmap_t bool is_empty () const { return population == 0; } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (auto pair : iter ()) + h ^= (hb_hash (pair.first) * 31) + hb_hash (pair.second); + return h; + } + + bool is_equal (const hb_hashmap_t &other) const + { + if (population != other.population) return false; + + for (auto pair : iter ()) + if (get (pair.first) != pair.second) + return false; + + return true; + } + bool operator == (const hb_hashmap_t &other) const { return is_equal (other); } + bool operator != (const hb_hashmap_t &other) const { return !is_equal (other); } + unsigned int get_population () const { return population; } /* @@ -248,11 +296,13 @@ struct hb_hashmap_t bool set_with_hash (K key, uint32_t hash, VV&& value) { if (unlikely (!successful)) return false; - if (unlikely (key == kINVALID)) return true; + const K kinv = hb_coerce<K> (kINVALID); + if (unlikely (key == kinv)) return true; if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; unsigned int i = bucket_for_hash (key, hash); - if (value == vINVALID && items[i].key != key) + const V vinv = hb_coerce<V> (vINVALID); + if (value == vinv && items[i].key != key) return true; /* Trying to delete non-existent key. */ if (!items[i].is_unused ()) @@ -364,9 +414,11 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t, HB_MAP_VALUE_INVALID, HB_MAP_VALUE_INVALID>; - hb_map_t () = default; ~hb_map_t () = default; - hb_map_t (hb_map_t&) = default; + hb_map_t () : hashmap () {} + hb_map_t (std::nullptr_t) : hb_map_t () {} + hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {} + hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} hb_map_t& operator= (const hb_map_t&) = default; hb_map_t& operator= (hb_map_t&&) = default; hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {} diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh index 0ea5774a9f..90757d38ac 100644 --- a/thirdparty/harfbuzz/src/hb-meta.hh +++ b/thirdparty/harfbuzz/src/hb-meta.hh @@ -29,6 +29,7 @@ #include "hb.hh" +#include <memory> #include <type_traits> #include <utility> @@ -85,30 +86,13 @@ template <> struct hb_priority<0> {}; template <typename T> struct hb_type_identity_t { typedef T type; }; template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type; -struct -{ - template <typename T> constexpr T* - operator () (T& arg) const - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-align" - /* https://en.cppreference.com/w/cpp/memory/addressof */ - return reinterpret_cast<T*> ( - &const_cast<char&> ( - reinterpret_cast<const volatile char&> (arg))); -#pragma GCC diagnostic pop - } -} -HB_FUNCOBJ (hb_addressof); - template <typename T> static inline T hb_declval (); #define hb_declval(T) (hb_declval<T> ()) template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> using hb_remove_const = typename hb_match_const<T>::type; -template <typename T> using hb_add_const = const T; -#define hb_is_const(T) hb_match_const<T>::value + template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_true_type {}; @@ -119,14 +103,13 @@ template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lval template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>; template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>; template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize)); -#define hb_is_reference(T) hb_match_reference<T>::value + template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type; template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>; template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>; template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize)); -#define hb_is_pointer(T) hb_match_pointer<T>::value /* TODO Add feature-parity to std::decay. */ @@ -137,8 +120,8 @@ template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>; template <typename From, typename To> using hb_is_cr_convertible = hb_bool_constant< hb_is_same (hb_decay<From>, hb_decay<To>) && - (!hb_is_const (From) || hb_is_const (To)) && - (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To)) + (!std::is_const<From>::value || std::is_const<To>::value) && + (!std::is_reference<To>::value || std::is_const<To>::value || std::is_reference<To>::value) >; #define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value @@ -153,16 +136,6 @@ struct } HB_FUNCOBJ (hb_deref); -struct -{ - template <typename T> constexpr auto - operator () (T&& v) const HB_AUTO_RETURN (std::forward<T> (v)) - - template <typename T> constexpr auto - operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v)) -} -HB_FUNCOBJ (hb_ref); - template <typename T> struct hb_reference_wrapper { @@ -176,7 +149,7 @@ struct hb_reference_wrapper template <typename T> struct hb_reference_wrapper<T&> { - hb_reference_wrapper (T& v) : v (hb_addressof (v)) {} + hb_reference_wrapper (T& v) : v (std::addressof (v)) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } operator T& () const { return *v; } @@ -215,6 +188,19 @@ template <> struct hb_int_max<signed long long> : hb_integral_constant<signed l template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigned long long, ULLONG_MAX> {}; #define hb_int_max(T) hb_int_max<T>::value +#if __GNUG__ && __GNUC__ < 5 +#define hb_is_trivially_copyable(T) __has_trivial_copy(T) +#define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T) +#define hb_is_trivially_constructible(T) __has_trivial_constructor(T) +#define hb_is_trivially_copy_constructible(T) __has_trivial_copy_constructor(T) +#define hb_is_trivially_destructible(T) __has_trivial_destructor(T) +#else +#define hb_is_trivially_copyable(T) std::is_trivially_copyable<T>::value +#define hb_is_trivially_copy_assignable(T) std::is_trivially_copy_assignable<T>::value +#define hb_is_trivially_constructible(T) std::is_trivially_constructible<T>::value +#define hb_is_trivially_copy_constructible(T) std::is_trivially_copy_constructible<T>::value +#define hb_is_trivially_destructible(T) std::is_trivially_destructible<T>::value +#endif /* Class traits. */ diff --git a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc deleted file mode 100644 index 6d09b252d8..0000000000 --- a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright © 2011,2012,2013 Google, Inc. - * Copyright © 2021 Khaled Hosny - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb-ms-feature-ranges.hh" - -bool -hb_ms_setup_features (const hb_feature_t *features, - unsigned int num_features, - hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */ - hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */) -{ - feature_records.shrink(0); - range_records.shrink(0); - - /* Sort features by start/end events. */ - hb_vector_t<hb_ms_feature_event_t> feature_events; - for (unsigned int i = 0; i < num_features; i++) - { - hb_ms_active_feature_t feature; - feature.fea.tag_le = hb_uint32_swap (features[i].tag); - feature.fea.value = features[i].value; - feature.order = i; - - hb_ms_feature_event_t *event; - - event = feature_events.push (); - event->index = features[i].start; - event->start = true; - event->feature = feature; - - event = feature_events.push (); - event->index = features[i].end; - event->start = false; - event->feature = feature; - } - feature_events.qsort (); - /* Add a strategic final event. */ - { - hb_ms_active_feature_t feature; - feature.fea.tag_le = 0; - feature.fea.value = 0; - feature.order = num_features + 1; - - auto *event = feature_events.push (); - event->index = 0; /* This value does magic. */ - event->start = false; - event->feature = feature; - } - - /* Scan events and save features for each range. */ - hb_vector_t<hb_ms_active_feature_t> active_features; - unsigned int last_index = 0; - for (unsigned int i = 0; i < feature_events.length; i++) - { - auto *event = &feature_events[i]; - - if (event->index != last_index) - { - /* Save a snapshot of active features and the range. */ - auto *range = range_records.push (); - auto offset = feature_records.length; - - active_features.qsort (); - for (unsigned int j = 0; j < active_features.length; j++) - { - if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le) - { - feature_records.push (active_features[j].fea); - } - else - { - /* Overrides value for existing feature. */ - feature_records[feature_records.length - 1].value = active_features[j].fea.value; - } - } - - /* Will convert to pointer after all is ready, since feature_records.array - * may move as we grow it. */ - range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset); - range->features.num_features = feature_records.length - offset; - range->index_first = last_index; - range->index_last = event->index - 1; - - last_index = event->index; - } - - if (event->start) - { - active_features.push (event->feature); - } - else - { - auto *feature = active_features.find (&event->feature); - if (feature) - active_features.remove (feature - active_features.arrayZ); - } - } - - if (!range_records.length) /* No active feature found. */ - num_features = 0; - - /* Fixup the pointers. */ - for (unsigned int i = 0; i < range_records.length; i++) - { - auto *range = &range_records[i]; - range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features); - } - - return !!num_features; -} - -void -hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records, - hb_vector_t<hb_ms_range_record_t> &range_records, - unsigned int chars_offset, - unsigned int chars_len, - uint16_t *log_clusters, - hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */ - hb_vector_t<uint32_t> &range_counts /* OUT */) -{ - range_features.shrink (0); - range_counts.shrink (0); - - auto *last_range = &range_records[0]; - for (unsigned int i = chars_offset; i < chars_len; i++) - { - auto *range = last_range; - while (log_clusters[i] < range->index_first) - range--; - while (log_clusters[i] > range->index_last) - range++; - if (!range_features.length || - &range->features != range_features[range_features.length - 1]) - { - auto **features = range_features.push (); - auto *c = range_counts.push (); - if (unlikely (!features || !c)) - { - range_features.shrink (0); - range_counts.shrink (0); - break; - } - *features = &range->features; - *c = 1; - } - else - { - range_counts[range_counts.length - 1]++; - } - - last_range = range; - } -} diff --git a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh index 401d1e1d97..d40fdeaa82 100644 --- a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh +++ b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh @@ -52,8 +52,8 @@ struct hb_ms_active_feature_t { a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 : 0; } - bool operator== (const hb_ms_active_feature_t *f) - { return cmp (this, f) == 0; } + bool operator== (const hb_ms_active_feature_t& f) const + { return cmp (this, &f) == 0; } }; struct hb_ms_feature_event_t { @@ -77,20 +77,153 @@ struct hb_ms_range_record_t { unsigned int index_last; /* == end - 1 */ }; -HB_INTERNAL bool +static inline bool hb_ms_setup_features (const hb_feature_t *features, unsigned int num_features, hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */ - hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */); + hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */) +{ + feature_records.shrink(0); + range_records.shrink(0); + /* Sort features by start/end events. */ + hb_vector_t<hb_ms_feature_event_t> feature_events; + for (unsigned int i = 0; i < num_features; i++) + { + hb_ms_active_feature_t feature; + feature.fea.tag_le = hb_uint32_swap (features[i].tag); + feature.fea.value = features[i].value; + feature.order = i; + + hb_ms_feature_event_t *event; + + event = feature_events.push (); + event->index = features[i].start; + event->start = true; + event->feature = feature; + + event = feature_events.push (); + event->index = features[i].end; + event->start = false; + event->feature = feature; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + hb_ms_active_feature_t feature; + feature.fea.tag_le = 0; + feature.fea.value = 0; + feature.order = num_features + 1; + + auto *event = feature_events.push (); + event->index = 0; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_vector_t<hb_ms_active_feature_t> active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.length; i++) + { + auto *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + auto *range = range_records.push (); + auto offset = feature_records.length; + + active_features.qsort (); + for (unsigned int j = 0; j < active_features.length; j++) + { + if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le) + { + feature_records.push (active_features[j].fea); + } + else + { + /* Overrides value for existing feature. */ + feature_records[feature_records.length - 1].value = active_features[j].fea.value; + } + } + + /* Will convert to pointer after all is ready, since feature_records.array + * may move as we grow it. */ + range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset); + range->features.num_features = feature_records.length - offset; + range->index_first = last_index; + range->index_last = event->index - 1; -HB_INTERNAL void + last_index = event->index; + } + + if (event->start) + { + active_features.push (event->feature); + } + else + { + auto *feature = active_features.lsearch (event->feature); + if (feature) + active_features.remove (feature - active_features.arrayZ); + } + } + + if (!range_records.length) /* No active feature found. */ + num_features = 0; + + /* Fixup the pointers. */ + for (unsigned int i = 0; i < range_records.length; i++) + { + auto *range = &range_records[i]; + range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features); + } + + return !!num_features; +} + +static inline void hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records, hb_vector_t<hb_ms_range_record_t> &range_records, unsigned int chars_offset, unsigned int chars_len, uint16_t *log_clusters, hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */ - hb_vector_t<uint32_t> &range_counts /* OUT */); + hb_vector_t<uint32_t> &range_counts /* OUT */) +{ + range_features.shrink (0); + range_counts.shrink (0); + + auto *last_range = &range_records[0]; + for (unsigned int i = chars_offset; i < chars_len; i++) + { + auto *range = last_range; + while (log_clusters[i] < range->index_first) + range--; + while (log_clusters[i] > range->index_last) + range++; + if (!range_features.length || + &range->features != range_features[range_features.length - 1]) + { + auto **features = range_features.push (); + auto *c = range_counts.push (); + if (unlikely (!features || !c)) + { + range_features.shrink (0); + range_counts.shrink (0); + break; + } + *features = &range->features; + *c = 1; + } + else + { + range_counts[range_counts.length - 1]++; + } + + last_range = range; + } +} #endif /* HB_MS_FEATURE_RANGES_HH */ diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh index 0e15cb12c4..4b5bc32ade 100644 --- a/thirdparty/harfbuzz/src/hb-object.hh +++ b/thirdparty/harfbuzz/src/hb-object.hh @@ -53,7 +53,7 @@ struct hb_lockable_set_t item_t *replace_or_insert (T v, lock_t &l, bool replace) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) { if (replace) { item_t old = *item; @@ -76,7 +76,7 @@ struct hb_lockable_set_t void remove (T v, lock_t &l) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) { item_t old = *item; @@ -93,7 +93,7 @@ struct hb_lockable_set_t bool find (T v, item_t *i, lock_t &l) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) *i = *item; l.unlock (); diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh index 7e524177f6..aee7064be3 100644 --- a/thirdparty/harfbuzz/src/hb-open-type.hh +++ b/thirdparty/harfbuzz/src/hb-open-type.hh @@ -33,6 +33,7 @@ #include "hb-blob.hh" #include "hb-face.hh" #include "hb-machinery.hh" +#include "hb-meta.hh" #include "hb-subset.hh" @@ -518,7 +519,7 @@ struct UnsizedArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); @@ -707,7 +708,7 @@ struct ArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -835,7 +836,7 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -884,7 +885,7 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -1070,7 +1071,7 @@ struct VarSizedBinSearchArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh index 180c87cb89..ae3b83a256 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh @@ -46,51 +46,21 @@ template<typename Type> static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) { return offset ? StructAtOffset<Type> (P, offset) : Null (Type); } -inline unsigned int calcOffSize (unsigned int dataSize) -{ - unsigned int size = 1; - unsigned int offset = dataSize + 1; - while (offset & ~0xFF) - { - size++; - offset >>= 8; - } - /* format does not support size > 4; caller should handle it as an error */ - return size; -} - struct code_pair_t { hb_codepoint_t code; hb_codepoint_t glyph; }; -typedef hb_vector_t<unsigned char> str_buff_t; -struct str_buff_vec_t : hb_vector_t<str_buff_t> -{ - void fini () { SUPER::fini_deep (); } - - unsigned int total_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < length; i++) - size += (*this)[i].length; - return size; - } - - private: - typedef hb_vector_t<str_buff_t> SUPER; -}; +using str_buff_t = hb_vector_t<unsigned char>; +using str_buff_vec_t = hb_vector_t<str_buff_t>; /* CFF INDEX */ template <typename COUNT> struct CFFIndex { - static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) - { return offSize * (count + 1); } - unsigned int offset_array_size () const - { return calculate_offset_array_size (offSize, count); } + { return offSize * (count + 1); } CFFIndex *copy (hb_serialize_context_t *c) const { @@ -102,55 +72,46 @@ struct CFFIndex return_trace (out); } - bool serialize (hb_serialize_context_t *c, const CFFIndex &src) - { - TRACE_SERIALIZE (this); - unsigned int size = src.get_size (); - CFFIndex *dest = c->allocate_size<CFFIndex> (size); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); - return_trace (true); - } - bool serialize (hb_serialize_context_t *c, unsigned int offSize_, const byte_str_array_t &byteArray) { TRACE_SERIALIZE (this); + if (byteArray.length == 0) { COUNT *dest = c->allocate_min<COUNT> (); if (unlikely (!dest)) return_trace (false); *dest = 0; + return_trace (true); } - else - { - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) - return_trace (false); - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (this))) return_trace (false); + this->count = byteArray.length; + this->offSize = offSize_; + if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (; i < byteArray.length; i++) + { set_offset_at (i, offset); + offset += byteArray[i].get_size (); + } + set_offset_at (i, offset); - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const byte_str_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size<unsigned char> (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } + /* serialize data */ + for (unsigned int i = 0; i < byteArray.length; i++) + { + const hb_ubytes_t &bs = byteArray[i]; + unsigned char *dest = c->allocate_size<unsigned char> (bs.length); + if (unlikely (!dest)) return_trace (false); + memcpy (dest, &bs[0], bs.length); } + return_trace (true); } @@ -162,7 +123,7 @@ struct CFFIndex byteArray.init (); byteArray.resize (buffArray.length); for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length); + byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); bool result = this->serialize (c, offSize_, byteArray); byteArray.fini (); return result; @@ -174,18 +135,9 @@ struct CFFIndex Iterator it) { TRACE_SERIALIZE (this); - if (it.len () == 0) - { - COUNT *dest = c->allocate_min<COUNT> (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - } - else - { - serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); - for (const auto &_ : +it) - _.copy (c); - } + serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); + for (const auto &_ : +it) + _.copy (c); return_trace (true); } @@ -198,7 +150,7 @@ struct CFFIndex { auto it = + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) ; return serialize (c, it); } @@ -211,13 +163,15 @@ struct CFFIndex TRACE_SERIALIZE (this); unsigned total = + it | hb_reduce (hb_add, 0); - unsigned off_size = calcOffSize (total); + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; /* serialize CFFIndex header */ if (unlikely (!c->extend_min (this))) return_trace (false); this->count = it.len (); + if (!this->count) return_trace (true); + if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; - if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1)))) + if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1)))) return_trace (false); /* serialize indices */ @@ -235,6 +189,7 @@ struct CFFIndex void set_offset_at (unsigned int index, unsigned int offset) { + assert (index <= count); HBUINT8 *p = offsets + offSize * index + offSize; unsigned int size = offSize; for (; size; size--) @@ -245,11 +200,13 @@ struct CFFIndex } } + private: unsigned int offset_at (unsigned int index) const { assert (index <= count); - const HBUINT8 *p = offsets + offSize * index; + unsigned int size = offSize; + const HBUINT8 *p = offsets + size * index; unsigned int offset = 0; for (; size; size--) offset = (offset << 8) + *p++; @@ -258,72 +215,57 @@ struct CFFIndex unsigned int length_at (unsigned int index) const { - if (unlikely ((offset_at (index + 1) < offset_at (index)) || - (offset_at (index + 1) > offset_at (count)))) + unsigned offset0 = offset_at (index); + unsigned offset1 = offset_at (index + 1); + if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) return 0; - return offset_at (index + 1) - offset_at (index); + return offset1 - offset0; } const unsigned char *data_base () const - { return (const unsigned char *) this + min_size + offset_array_size (); } - - unsigned int data_size () const { return HBINT8::static_size; } + { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); } + public: - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { - if (unlikely (index >= count)) return Null (byte_str_t); - return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); + if (unlikely (index >= count)) return hb_ubytes_t (); + unsigned length = length_at (index); + if (unlikely (!length)) return hb_ubytes_t (); + return hb_ubytes_t (data_base () + offset_at (index) - 1, length); } unsigned int get_size () const { - if (this == &Null (CFFIndex)) return 0; - if (count > 0) - return min_size + offset_array_size () + (offset_at (count) - 1); - return count.static_size; /* empty CFFIndex contains count only */ + if (count) + return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + return min_size; /* empty CFFIndex contains count only */ } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */ - (c->check_struct (this) && offSize >= 1 && offSize <= 4 && - c->check_array (offsets, offSize, count + 1) && - c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1)))); - } - - protected: - unsigned int max_offset () const - { - unsigned int max = 0; - for (unsigned int i = 0; i < count + 1u; i++) - { - unsigned int off = offset_at (i); - if (off > max) max = off; - } - return max; + return_trace (likely (c->check_struct (this) && + (count == 0 || /* empty INDEX */ + (count < count + 1u && + c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1u) && + c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1))))); } public: COUNT count; /* Number of object data. Note there are (count+1) offsets */ + private: HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ HBUINT8 offsets[HB_VAR_ARRAY]; /* The array of (count + 1) offsets into objects array (1-base). */ /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ public: - DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); + DEFINE_SIZE_MIN (COUNT::static_size); }; template <typename COUNT, typename TYPE> struct CFFIndexOf : CFFIndex<COUNT> { - const byte_str_t operator [] (unsigned int index) const - { - if (likely (index < CFFIndex<COUNT>::count)) - return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index)); - return Null (byte_str_t); - } - template <typename DATA, typename PARAM1, typename PARAM2> bool serialize (hb_serialize_context_t *c, unsigned int offSize_, diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc index 3298fa35ae..bd9fe5d6d4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc @@ -311,10 +311,8 @@ struct bounds_t struct cff1_extents_param_t { - void init (const OT::cff1::accelerator_t *_cff) + cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) { - path_open = false; - cff = _cff; bounds.init (); } @@ -322,7 +320,7 @@ struct cff1_extents_param_t void end_path () { path_open = false; } bool is_path_open () const { return path_open; } - bool path_open; + bool path_open = false; bounds_t bounds; const OT::cff1::accelerator_t *cff; @@ -395,12 +393,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); - cff1_extents_param_t param; - param.init (cff); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env); + cff1_extents_param_t param (cff); if (unlikely (!interp.interpret (param))) return false; bounds = param.bounds; return true; @@ -442,13 +439,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph return true; } -#ifdef HB_EXPERIMENTAL_API struct cff1_path_param_t { cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_, - draw_helper_t &draw_helper_, point_t *delta_) + hb_draw_session_t &draw_session_, point_t *delta_) { - draw_helper = &draw_helper_; + draw_session = &draw_session_; cff = cff_; font = font_; delta = delta_; @@ -458,14 +454,14 @@ struct cff1_path_param_t { point_t point = p; if (delta) point.move (*delta); - draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ())); } void line_to (const point_t &p) { point_t point = p; if (delta) point.move (*delta); - draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ())); } void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) @@ -477,15 +473,15 @@ struct cff1_path_param_t point2.move (*delta); point3.move (*delta); } - draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()), - font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()), - font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ())); + draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()), + font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()), + font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ())); } - void end_path () { draw_helper->end_path (); } + void end_path () { draw_session->close_path (); } hb_font_t *font; - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; point_t *delta; const OT::cff1::accelerator_t *cff; @@ -513,7 +509,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int }; static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, - draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr); + hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr); struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t> { @@ -530,23 +526,23 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); if (unlikely (!(!env.in_seac && base && accent - && _get_path (param.cff, param.font, base, *param.draw_helper, true) - && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta)))) + && _get_path (param.cff, param.font, base, *param.draw_session, true) + && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta)))) env.set_error (); } }; bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, - draw_helper_t &draw_helper, bool in_seac, point_t *delta) + hb_draw_session_t &draw_session, bool in_seac, point_t *delta) { if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); - cff1_path_param_t param (cff, font, draw_helper, delta); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env); + cff1_path_param_t param (cff, font, draw_session, delta); if (unlikely (!interp.interpret (param))) return false; /* Let's end the path specially since it is called inside seac also */ @@ -555,31 +551,25 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } -bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - return _get_path (this, font, glyph, draw_helper); + return _get_path (this, font, glyph, draw_session); } -#endif struct get_seac_param_t { - void init (const OT::cff1::accelerator_t *_cff) - { - cff = _cff; - base = 0; - accent = 0; - } + get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {} bool has_seac () const { return base && accent; } const OT::cff1::accelerator_t *cff; - hb_codepoint_t base; - hb_codepoint_t accent; + hb_codepoint_t base = 0; + hb_codepoint_t accent = 0; }; struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t> @@ -600,11 +590,10 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd); - get_seac_param_t param; - param.init (this); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *this, fd); + cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env); + get_seac_param_t param (this); if (unlikely (!interp.interpret (param))) return false; if (param.has_seac ()) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh index 5dd183e3a0..b5047002ac 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @@ -318,14 +318,21 @@ struct Charset0 { return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; else return sids[glyph - 1]; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) + mapping->set (gid, sids[gid - 1]); + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) @@ -381,20 +388,36 @@ struct Charset1_2 { return_trace (true); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; glyph--; for (unsigned int i = 0;; i++) { if (glyph <= ranges[i].nLeft) - return (hb_codepoint_t)ranges[i].first + glyph; + return (hb_codepoint_t) ranges[i].first + glyph; glyph -= (ranges[i].nLeft + 1); } return 0; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + hb_codepoint_t gid = 1; + for (unsigned i = 0;; i++) + { + hb_codepoint_t sid = ranges[i].first; + unsigned count = ranges[i].nLeft + 1; + for (unsigned j = 0; j < count; j++) + mapping->set (gid++, sid++); + + if (gid >= num_glyphs) + break; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) return 0; @@ -521,16 +544,26 @@ struct Charset hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const { - if (unlikely (glyph >= num_glyphs)) return 0; switch (format) { - case 0: return u.format0.get_sid (glyph); - case 1: return u.format1.get_sid (glyph); - case 2: return u.format2.get_sid (glyph); + case 0: return u.format0.get_sid (glyph, num_glyphs); + case 1: return u.format1.get_sid (glyph, num_glyphs); + case 2: return u.format2.get_sid (glyph, num_glyphs); default:return 0; } } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + switch (format) + { + case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; + default:return; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { switch (format) @@ -602,6 +635,8 @@ struct cff1_top_dict_interp_env_t : num_interp_env_t { cff1_top_dict_interp_env_t () : num_interp_env_t(), prev_offset(0), last_offset(0) {} + cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes) + : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {} unsigned int prev_offset; unsigned int last_offset; @@ -1024,11 +1059,10 @@ struct cff1 { fini (); return; } { /* parse top dict */ - const byte_str_t topDictStr = (*topDictIndex)[0]; + const hb_ubytes_t topDictStr = (*topDictIndex)[0]; if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } - cff1_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); - topDict.init (); + cff1_top_dict_interp_env_t env (topDictStr); + cff1_top_dict_interpreter_t top_interp (env); if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } } @@ -1098,20 +1132,20 @@ struct cff1 { for (unsigned int i = 0; i < fdCount; i++) { - byte_str_t fontDictStr = (*fdArray)[i]; + hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } cff1_font_dict_values_t *font; - cff1_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + cff1_top_dict_interp_env_t env (fontDictStr); + cff1_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } PRIVDICTVAL *priv = &privateDicts[i]; - const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env2 (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1126,10 +1160,10 @@ struct cff1 cff1_top_dict_values_t *font = &topDict; PRIVDICTVAL *priv = &privateDicts[0]; - const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1144,8 +1178,8 @@ struct cff1 { sc.end_processing (); topDict.fini (); - fontDicts.fini_deep (); - privateDicts.fini_deep (); + fontDicts.fini (); + privateDicts.fini (); hb_blob_destroy (blob); blob = nullptr; } @@ -1194,6 +1228,19 @@ struct cff1 } } + hb_map_t *create_glyph_to_sid_map () const + { + if (charset != &Null (Charset)) + { + hb_map_t *mapping = hb_map_create (); + mapping->set (0, 0); + charset->collect_glyph_to_sid_map (mapping, num_glyphs); + return mapping; + } + else + return nullptr; + } + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const { if (charset != &Null (Charset)) @@ -1245,60 +1292,49 @@ struct cff1 } protected: - hb_blob_t *blob; + hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: - const Encoding *encoding; - const Charset *charset; - const CFF1NameIndex *nameIndex; - const CFF1TopDictIndex *topDictIndex; - const CFF1StringIndex *stringIndex; - const CFF1Subrs *globalSubrs; - const CFF1CharStrings *charStrings; - const CFF1FDArray *fdArray; - const CFF1FDSelect *fdSelect; - unsigned int fdCount; + const Encoding *encoding = nullptr; + const Charset *charset = nullptr; + const CFF1NameIndex *nameIndex = nullptr; + const CFF1TopDictIndex *topDictIndex = nullptr; + const CFF1StringIndex *stringIndex = nullptr; + const CFF1Subrs *globalSubrs = nullptr; + const CFF1CharStrings *charStrings = nullptr; + const CFF1FDArray *fdArray = nullptr; + const CFF1FDSelect *fdSelect = nullptr; + unsigned int fdCount = 0; cff1_top_dict_values_t topDict; hb_vector_t<cff1_font_dict_values_t> fontDicts; hb_vector_t<PRIVDICTVAL> privateDicts; - unsigned int num_glyphs; + unsigned int num_glyphs = 0; }; struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { SUPER::init (face); + glyph_names.set_relaxed (nullptr); + if (!is_valid ()) return; if (is_CID ()) return; - /* fill glyph_names */ - for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) - { - hb_codepoint_t sid = glyph_to_sid (gid); - gname_t gname; - gname.sid = sid; - if (sid < cff1_std_strings_length) - gname.name = cff1_std_strings (sid); - else - { - byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; - gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length); - } - if (unlikely (!gname.name.arrayZ)) { fini (); return; } - glyph_names.push (gname); - } - glyph_names.qsort (); } - - void fini () + ~accelerator_t () { - glyph_names.fini (); + hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed (); + if (names) + { + names->fini (); + free (names); + } SUPER::fini (); } @@ -1306,9 +1342,9 @@ struct cff1 bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { - if (!buf) return true; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; + if (unlikely (!buf_len)) return true; hb_codepoint_t sid = glyph_to_sid (glyph); const char *str; size_t str_len; @@ -1320,7 +1356,7 @@ struct cff1 } else { - byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; + hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; str = (const char *)ubyte_str.arrayZ; str_len = ubyte_str.length; } @@ -1334,11 +1370,53 @@ struct cff1 bool get_glyph_from_name (const char *name, int len, hb_codepoint_t *glyph) const { + if (unlikely (!is_valid ())) return false; + if (is_CID()) return false; if (len < 0) len = strlen (name); if (unlikely (!len)) return false; + retry: + hb_sorted_vector_t<gname_t> *names = glyph_names.get (); + if (unlikely (!names)) + { + names = (hb_sorted_vector_t<gname_t> *) calloc (sizeof (hb_sorted_vector_t<gname_t>), 1); + if (likely (names)) + { + names->init (); + /* TODO */ + + /* fill glyph names */ + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t sid = glyph_to_sid (gid); + gname_t gname; + gname.sid = sid; + if (sid < cff1_std_strings_length) + gname.name = cff1_std_strings (sid); + else + { + hb_ubytes_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; + gname.name = hb_bytes_t ((const char*) ustr.arrayZ, ustr.length); + } + if (unlikely (!gname.name.arrayZ)) + gname.name = hb_bytes_t ("", 0); /* To avoid nullptr. */ + names->push (gname); + } + names->qsort (); + } + if (unlikely (!glyph_names.cmpexch (nullptr, names))) + { + if (names) + { + names->fini (); + free (names); + } + goto retry; + } + } + gname_t key = { hb_bytes_t (name, len), 0 }; - const gname_t *gname = glyph_names.bsearch (key); + const gname_t *gname = glyph_names->bsearch (key); if (!gname) return false; hb_codepoint_t gid = sid_to_glyph (gname->sid); if (!gid && gname->sid) return false; @@ -1348,9 +1426,7 @@ struct cff1 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; -#ifdef HB_EXPERIMENTAL_API - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; -#endif + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; private: struct gname_t @@ -1362,7 +1438,7 @@ struct cff1 { const gname_t *a = (const gname_t *)a_; const gname_t *b = (const gname_t *)b_; - int minlen = hb_min (a->name.length, b->name.length); + unsigned minlen = hb_min (a->name.length, b->name.length); int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); if (ret) return ret; return a->name.length - b->name.length; @@ -1371,7 +1447,7 @@ struct cff1 int cmp (const gname_t &a) const { return cmp (&a, this); } }; - hb_sorted_vector_t<gname_t> glyph_names; + mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names; typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER; }; @@ -1398,7 +1474,10 @@ struct cff1 DEFINE_SIZE_STATIC (4); }; -struct cff1_accelerator_t : cff1::accelerator_t {}; +struct cff1_accelerator_t : cff1::accelerator_t { + cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF1_TABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc index 879b7cdb23..50c76daf93 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc @@ -36,9 +36,8 @@ using namespace CFF; struct cff2_extents_param_t { - void init () + cff2_extents_param_t () { - path_open = false; min_x.set_int (INT_MAX); min_y.set_int (INT_MAX); max_x.set_int (INT_MIN); @@ -57,22 +56,22 @@ struct cff2_extents_param_t if (pt.y > max_y) max_y = pt.y; } - bool path_open; + bool path_open = false; number_t min_x; number_t min_y; number_t max_x; number_t max_y; }; -struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t> +struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -83,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_ param.update_bounds (env.get_pt ()); } - static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { if (!param.is_path_open ()) { @@ -98,7 +97,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_ } }; -struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {}; +struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -112,11 +111,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env); cff2_extents_param_t param; - param.init (); if (unlikely (!interp.interpret (param))) return false; if (param.min_x >= param.max_x) @@ -143,57 +141,56 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, return true; } -#ifdef HB_EXPERIMENTAL_API struct cff2_path_param_t { - cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_) + cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { - draw_helper = &draw_helper_; + draw_session = &draw_session_; font = font_; } void move_to (const point_t &p) - { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } void line_to (const point_t &p) - { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) { - draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()), - font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()), - font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ())); + draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()), + font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()), + font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ())); } protected: - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; hb_font_t *font; }; -struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t> +struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt) { param.move_to (pt); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1) { param.line_to (pt1); env.moveto (pt1); } - static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { param.cubic_to (pt1, pt2, pt3); env.moveto (pt3); } }; -struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {}; +struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {}; -bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -203,13 +200,12 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); - cff2_path_param_t param (font, draw_helper); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env); + cff2_path_param_t param (font, draw_session); if (unlikely (!interp.interpret (param))) return false; return true; } -#endif #endif diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh index 829217feaa..746160dc8e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh @@ -247,12 +247,8 @@ typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values struct cff2_priv_dict_interp_env_t : num_interp_env_t { - void init (const byte_str_t &str) - { - num_interp_env_t::init (str); - ivs = 0; - seen_vsindex = false; - } + cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) : + num_interp_env_t (str) {} void process_vsindex () { @@ -267,8 +263,8 @@ struct cff2_priv_dict_interp_env_t : num_interp_env_t void set_ivs (unsigned int ivs_) { ivs = ivs_; } protected: - unsigned int ivs; - bool seen_vsindex; + unsigned int ivs = 0; + bool seen_vsindex = false; }; struct cff2_private_dict_opset_t : dict_opset_t @@ -397,7 +393,7 @@ struct cff2 template <typename PRIVOPSET, typename PRIVDICTVAL> struct accelerator_templ_t { - void init (hb_face_t *face) + accelerator_templ_t (hb_face_t *face) { topDict.init (); fontDicts.init (); @@ -412,15 +408,15 @@ struct cff2 const OT::cff2 *cff2 = this->blob->template as<OT::cff2> (); if (cff2 == &Null (OT::cff2)) - { fini (); return; } + goto fail; { /* parse top dict */ - byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); - if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } - cff2_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); + hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); + if (unlikely (!topDictStr.sanitize (&sc))) goto fail; + num_interp_env_t env (topDictStr); + cff2_top_dict_interpreter_t top_interp (env); topDict.init (); - if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + if (unlikely (!top_interp.interpret (topDict))) goto fail; } globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize); @@ -434,49 +430,55 @@ struct cff2 (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) - { fini (); return; } + goto fail; num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) - { fini (); return; } + goto fail; fdCount = fdArray->count; if (!privateDicts.resize (fdCount)) - { fini (); return; } + goto fail; /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) { - const byte_str_t fontDictStr = (*fdArray)[i]; - if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + const hb_ubytes_t fontDictStr = (*fdArray)[i]; + if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; cff2_font_dict_values_t *font; - cff2_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + num_interp_env_t env (fontDictStr); + cff2_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); - if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail; font->init (); - if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + if (unlikely (!font_interp.interpret (*font))) goto fail; - const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp; - priv_interp.env.init(privDictStr); + const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); + if (unlikely (!privDictStr.sanitize (&sc))) goto fail; + cff2_priv_dict_interp_env_t env2 (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2); privateDicts[i].init (); - if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } + if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset); if (privateDicts[i].localSubrs != &Null (CFF2Subrs) && unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) - { fini (); return; } + goto fail; } - } - void fini () + + return; + + fail: + _fini (); + } + ~accelerator_templ_t () { _fini (); } + void _fini () { sc.end_processing (); topDict.fini (); - fontDicts.fini_deep (); - privateDicts.fini_deep (); + fontDicts.fini (); + privateDicts.fini (); hb_blob_destroy (blob); blob = nullptr; } @@ -484,32 +486,32 @@ struct cff2 bool is_valid () const { return blob; } protected: - hb_blob_t *blob; + hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: cff2_top_dict_values_t topDict; - const CFF2Subrs *globalSubrs; - const CFF2VariationStore *varStore; - const CFF2CharStrings *charStrings; - const CFF2FDArray *fdArray; - const CFF2FDSelect *fdSelect; - unsigned int fdCount; + const CFF2Subrs *globalSubrs = nullptr; + const CFF2VariationStore *varStore = nullptr; + const CFF2CharStrings *charStrings = nullptr; + const CFF2FDArray *fdArray = nullptr; + const CFF2FDSelect *fdSelect = nullptr; + unsigned int fdCount = 0; hb_vector_t<cff2_font_dict_values_t> fontDicts; hb_vector_t<PRIVDICTVAL> privateDicts; - unsigned int num_glyphs; + unsigned int num_glyphs = 0; }; struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> { + accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {} + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; -#ifdef HB_EXPERIMENTAL_API - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; -#endif + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; }; typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; @@ -525,7 +527,10 @@ struct cff2 DEFINE_SIZE_STATIC (5); }; -struct cff2_accelerator_t : cff2::accelerator_t {}; +struct cff2_accelerator_t : cff2::accelerator_t { + cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF2_TABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh index d837adc788..7e96d9c8b3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh @@ -44,7 +44,7 @@ struct CmapSubtableFormat0 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -109,22 +109,26 @@ struct CmapSubtableFormat4 while (it) { // Start a new range - start_cp = (*it).first; - prev_run_start_cp = (*it).first; - run_start_cp = (*it).first; - end_cp = (*it).first; - last_gid = (*it).second; - run_length = 1; - prev_delta = 0; - - delta = (*it).second - (*it).first; + { + const auto& pair = *it; + start_cp = pair.first; + prev_run_start_cp = start_cp; + run_start_cp = start_cp; + end_cp = start_cp; + last_gid = pair.second; + run_length = 1; + prev_delta = 0; + } + + delta = last_gid - start_cp; mode = FIRST_SUB_RANGE; it++; while (it) { // Process range - hb_codepoint_t next_cp = (*it).first; - hb_codepoint_t next_gid = (*it).second; + const auto& pair = *it; + hb_codepoint_t next_cp = pair.first; + hb_codepoint_t next_gid = pair.second; if (next_cp != end_cp + 1) { // Current range is over, stop processing. break; @@ -282,23 +286,22 @@ struct CmapSubtableFormat4 } template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, - Iterator it, + Iterator it, HBUINT16 *endCode, HBUINT16 *startCode, HBINT16 *idDelta, unsigned segcount) { - hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid; - + it | hb_sink (cp_to_gid); + hb_map_t cp_to_gid { it }; HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); if (unlikely (!c->check_success (idRangeOffset))) return nullptr; if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; for (unsigned i : + hb_range (segcount) - | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) + | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) { idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i); for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++) @@ -323,22 +326,31 @@ struct CmapSubtableFormat4 { return _.first <= 0xFFFF; }) ; - if (format4_iter.len () == 0) return; + if (!format4_iter) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; this->format = 4; + hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid { + format4_iter + }; + //serialize endCode[], startCode[], idDelta[] HBUINT16* endCode = c->start_embed<HBUINT16> (); - unsigned segcount = serialize_find_segcount (format4_iter); - if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount))) + unsigned segcount = serialize_find_segcount (cp_to_gid.iter()); + if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount))) return; HBUINT16 *startCode = endCode + segcount + 1; HBINT16 *idDelta = ((HBINT16*)startCode) + segcount; - HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, + cp_to_gid.iter (), + endCode, + startCode, + idDelta, + segcount); if (unlikely (!c->check_success (idRangeOffset))) return; this->length = c->length () - table_initpos; @@ -369,7 +381,6 @@ struct CmapSubtableFormat4 { accelerator_t () {} accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } - ~accelerator_t () { fini (); } void init (const CmapSubtableFormat4 *subtable) { @@ -381,7 +392,6 @@ struct CmapSubtableFormat4 glyphIdArray = idRangeOffset + segCount; glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; } - void fini () {} bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { @@ -403,7 +413,7 @@ struct CmapSubtableFormat4 2, _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>, this->segCount + 1); - if (!found) + if (unlikely (!found)) return false; unsigned int i = found - endCount; @@ -423,7 +433,7 @@ struct CmapSubtableFormat4 gid += this->idDelta[i]; } gid &= 0xFFFFu; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -442,14 +452,14 @@ struct CmapSubtableFormat4 hb_codepoint_t start = this->startCount[i]; hb_codepoint_t end = this->endCount[i]; unsigned int rangeOffset = this->idRangeOffset[i]; + out->add_range(start, end); if (rangeOffset == 0) { for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) { hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } else @@ -458,11 +468,13 @@ struct CmapSubtableFormat4 { unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; if (unlikely (index >= this->glyphIdArrayLength)) + { + out->del_range (codepoint, end); break; + } hb_codepoint_t gid = this->glyphIdArray[index]; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } } @@ -471,6 +483,8 @@ struct CmapSubtableFormat4 void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping /* OUT */) const { + // TODO(grieger): optimize similar to collect_unicodes + // (ie. use add_range()) unsigned count = this->segCount; if (count && this->startCount[count - 1] == 0xFFFFu) count--; /* Skip sentinel segment. */ @@ -622,7 +636,7 @@ struct CmapSubtableTrimmed { /* Rely on our implicit array bound-checking. */ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -676,7 +690,7 @@ struct CmapSubtableTrimmed }; struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; -struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; +struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {}; template <typename T> struct CmapSubtableLongSegmented @@ -686,7 +700,7 @@ struct CmapSubtableLongSegmented bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -716,7 +730,7 @@ struct CmapSubtableLongSegmented if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) end = start + (hb_codepoint_t) num_glyphs - gid; - out->add_range (start, end); + out->add_range (start, hb_min (end, 0x10FFFFu)); } } @@ -724,11 +738,19 @@ struct CmapSubtableLongSegmented hb_map_t *mapping, /* OUT */ unsigned num_glyphs) const { + hb_codepoint_t last_end = 0; for (unsigned i = 0; i < this->groups.len; i++) { hb_codepoint_t start = this->groups[i].startCharCode; hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, (hb_codepoint_t) HB_UNICODE_MAX); + if (unlikely (start > end || start < last_end)) { + // Range is not in order and is invalid, skip it. + continue; + } + last_end = end; + + hb_codepoint_t gid = this->groups[i].glyphID; if (!gid) { @@ -780,16 +802,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> void serialize (hb_serialize_context_t *c, Iterator it) { - if (it.len () == 0) return; + if (!it) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; - hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; + hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1; hb_codepoint_t glyphID = 0; for (const auto& _ : +it) { - if (startCharCode == 0xFFFF) + if (startCharCode == (hb_codepoint_t) -1) { startCharCode = _.first; endCharCode = _.first; @@ -820,7 +842,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> this->format = 12; this->reserved = 0; this->length = c->length () - table_initpos; - this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; + this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size; } static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data) @@ -885,7 +907,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange> hb_codepoint_t first = arrayZ[i].startUnicodeValue; hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), (hb_codepoint_t) HB_UNICODE_MAX); - out->add_range (first, last); + out->add_range (first, hb_min (last, 0x10FFFFu)); } } @@ -1450,6 +1472,37 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct SubtableUnicodesCache { + + private: + const void* base; + hb_hashmap_t<intptr_t, hb_set_t*> cached_unicodes; + + public: + SubtableUnicodesCache(const void* cmap_base) + : base(cmap_base), cached_unicodes() {} + ~SubtableUnicodesCache() + { + for (hb_set_t* s : cached_unicodes.values()) { + hb_set_destroy (s); + } + } + + hb_set_t* set_for(const EncodingRecord* record) + { + if (!cached_unicodes.has ((intptr_t) record)) { + hb_set_t* new_set = hb_set_create (); + if (!cached_unicodes.set ((intptr_t) record, new_set)) { + hb_set_destroy (new_set); + return hb_set_get_empty (); + } + (base+record->subtable).collect_unicodes (cached_unicodes.get ((intptr_t) record)); + } + return cached_unicodes.get ((intptr_t) record); + } + +}; + struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; @@ -1469,6 +1522,7 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); + SubtableUnicodesCache unicodes_cache (base); for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1477,12 +1531,11 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t unicodes_set; - (base+_.subtable).collect_unicodes (&unicodes_set); + hb_set_t* unicodes_set = unicodes_cache.set_for (&_); if (!drop_format_4 && format == 4) { - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx); + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx); if (c->in_error () && c->only_overflow ()) { // cmap4 overflowed, reset and retry serialization without format 4 subtables. @@ -1497,8 +1550,8 @@ struct cmap else if (format == 12) { - if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue; - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx); + if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); } @@ -1516,6 +1569,7 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, + SubtableUnicodesCache& unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1546,11 +1600,10 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t sibling_unicodes; - (base+_.subtable).collect_unicodes (&sibling_unicodes); + hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); - auto sibling = + subset_unicodes | hb_filter (sibling_unicodes); + auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); for (; cmap12 && sibling; cmap12++, sibling++) { unsigned a = *cmap12; @@ -1607,7 +1660,7 @@ struct cmap unsigned format = (this + _.subtable).u.format; if (format == 12) has_format12 = true; - const EncodingRecord *table = hb_addressof (_); + const EncodingRecord *table = std::addressof (_); if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table; else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table; else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table; @@ -1618,13 +1671,7 @@ struct cmap if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); auto it = - + hb_iter (c->plan->unicodes) - | hb_map ([&] (hb_codepoint_t _) - { - hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; - c->plan->new_gid_for_codepoint (_, &new_gid); - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid); - }) + + c->plan->unicode_to_new_gid_list.iter () | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return (_.second != HB_MAP_VALUE_INVALID); }) ; @@ -1665,7 +1712,7 @@ struct cmap struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<cmap> (face); bool symbol; @@ -1700,8 +1747,7 @@ struct cmap } } } - - void fini () { this->table.destroy (); } + ~accelerator_t () { this->table.destroy (); } bool get_nominal_glyph (hb_codepoint_t unicode, hb_codepoint_t *glyph) const @@ -1863,7 +1909,9 @@ struct cmap DEFINE_SIZE_ARRAY (4, encodingRecord); }; -struct cmap_accelerator_t : cmap::accelerator_t {}; +struct cmap_accelerator_t : cmap::accelerator_t { + cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh index 14459914ee..23fa56c4f6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh @@ -360,6 +360,16 @@ struct IndexSubtable struct IndexSubtableRecord { + /* XXX Remove this and fix by not inserting it into vector. */ + IndexSubtableRecord& operator = (const IndexSubtableRecord &o) + { + firstGlyphIndex = o.firstGlyphIndex; + lastGlyphIndex = o.lastGlyphIndex; + offsetToSubtable = (unsigned) o.offsetToSubtable; + assert (offsetToSubtable.is_null ()); + return *this; + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -809,15 +819,14 @@ struct CBDT struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { - cblc = hb_sanitize_context_t ().reference_table<CBLC> (face); - cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face); + this->cblc = hb_sanitize_context_t ().reference_table<CBLC> (face); + this->cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face); upem = hb_face_get_upem (face); } - - void fini () + ~accelerator_t () { this->cblc.destroy (); this->cbdt.destroy (); @@ -978,7 +987,10 @@ CBLC::subset (hb_subset_context_t *c) const return_trace (CBLC::sink_cbdt (c, &cbdt_prime)); } -struct CBDT_accelerator_t : CBDT::accelerator_t {}; +struct CBDT_accelerator_t : CBDT::accelerator_t { + CBDT_accelerator_t (hb_face_t *face) : CBDT::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh index 008422d089..dac755c02c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh @@ -71,7 +71,7 @@ struct hb_colrv1_closure_context_t : bool paint_visited (const void *paint) { hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); - if (visited_paint.has (delta)) + if (visited_paint.in_error() || visited_paint.has (delta)) return true; visited_paint.add (delta); @@ -1270,13 +1270,9 @@ struct COLR struct accelerator_t { - accelerator_t () {} - ~accelerator_t () { fini (); } - - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } - - void fini () { this->colr.destroy (); } + ~accelerator_t () { this->colr.destroy (); } bool is_valid () { return colr.get_blob ()->length; } @@ -1535,6 +1531,10 @@ struct COLR DEFINE_SIZE_MIN (14); }; +struct COLR_accelerator_t : COLR::accelerator_t { + COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh b/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh index ca85ba6ad6..fbaf2ec26b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh @@ -43,7 +43,7 @@ HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) con const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) { - const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i]; + const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i]; paint.dispatch (c); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh index a9deeba9a7..24476eda17 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh @@ -197,30 +197,38 @@ struct CPAL public: bool serialize (hb_serialize_context_t *c, - const hb_array_t<const BGRAColor> &color_records, const hb_array_t<const HBUINT16> &color_record_indices, - const hb_map_t &color_record_index_map, - const hb_set_t &retained_color_record_indices) const + const hb_array_t<const BGRAColor> &color_records, + const hb_vector_t<unsigned>& first_color_index_for_layer, + const hb_map_t& first_color_to_layer_index, + const hb_set_t &retained_color_indices) const { TRACE_SERIALIZE (this); + // TODO(grieger): limit total final size. + for (const auto idx : color_record_indices) { + hb_codepoint_t layer_index = first_color_to_layer_index[idx]; + HBUINT16 new_idx; - if (idx == 0) new_idx = 0; - else new_idx = color_record_index_map.get (idx); + new_idx = layer_index * retained_color_indices.get_population (); if (!c->copy<HBUINT16> (new_idx)) return_trace (false); } c->push (); - for (const auto _ : retained_color_record_indices.iter ()) + for (unsigned first_color_index : first_color_index_for_layer) { - if (!c->copy<BGRAColor> (color_records[_])) + for (hb_codepoint_t color_index : retained_color_indices) { - c->pop_discard (); - return_trace (false); + if (!c->copy<BGRAColor> (color_records[first_color_index + color_index])) + { + c->pop_discard (); + return_trace (false); + } } } + c->add_link (colorRecordsZ, c->pop_pack ()); return_trace (true); } @@ -228,6 +236,8 @@ struct CPAL bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + if (!numPalettes) return_trace (false); + const hb_map_t *color_index_map = c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); @@ -242,30 +252,34 @@ struct CPAL auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->version = version; out->numColors = retained_color_indices.get_population (); out->numPalettes = numPalettes; - const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); - hb_map_t color_record_index_map; - hb_set_t retained_color_record_indices; + hb_vector_t<unsigned> first_color_index_for_layer; + hb_map_t first_color_to_layer_index; - unsigned record_count = 0; + const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); for (const auto first_color_record_idx : colorRecordIndices) { - for (unsigned retained_color_idx : retained_color_indices.iter ()) - { - unsigned color_record_idx = first_color_record_idx + retained_color_idx; - if (color_record_index_map.has (color_record_idx)) continue; - color_record_index_map.set (color_record_idx, record_count); - retained_color_record_indices.add (color_record_idx); - record_count++; - } + if (first_color_to_layer_index.has (first_color_record_idx)) continue; + + first_color_index_for_layer.push (first_color_record_idx); + first_color_to_layer_index.set (first_color_record_idx, + first_color_index_for_layer.length - 1); } - out->numColorRecords = record_count; + out->numColorRecords = first_color_index_for_layer.length + * retained_color_indices.get_population (); + const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords); - if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices)) + if (!out->serialize (c->serializer, + colorRecordIndices, + color_records, + first_color_index_for_layer, + first_color_to_layer_index, + retained_color_indices)) return_trace (false); if (version == 1) diff --git a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh index d2911f19e6..9741ebd450 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh @@ -202,12 +202,12 @@ struct sbix struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<sbix> (face); num_glyphs = face->get_num_glyphs (); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } bool has_data () const { return table->has_data (); } @@ -407,7 +407,10 @@ struct sbix DEFINE_SIZE_ARRAY (8, strikes); }; -struct sbix_accelerator_t : sbix::accelerator_t {}; +struct sbix_accelerator_t : sbix::accelerator_t { + sbix_accelerator_t (hb_face_t *face) : sbix::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh index e022ef43b7..fc649f1006 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh @@ -79,9 +79,9 @@ struct SVG struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<SVG> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const { @@ -116,7 +116,9 @@ struct SVG DEFINE_SIZE_STATIC (10); }; -struct SVG_accelerator_t : SVG::accelerator_t {}; +struct SVG_accelerator_t : SVG::accelerator_t { + SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color.cc b/thirdparty/harfbuzz/src/hb-ot-color.cc index 4170b71317..16077765bd 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color.cc +++ b/thirdparty/harfbuzz/src/hb-ot-color.cc @@ -90,15 +90,15 @@ hb_ot_color_palette_get_count (hb_face_t *face) /** * hb_ot_color_palette_get_name_id: * @face: #hb_face_t to work upon - * @palette_index: The index of the color palette + * @palette_index: The index of the color palette * * Fetches the `name` table Name ID that provides display names for - * a `CPAL` color palette. + * a `CPAL` color palette. * * Palette display names can be generic (e.g., "Default") or provide * specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter"). * - * Return value: the Named ID found for the palette. + * Return value: the Named ID found for the palette. * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID. * * Since: 2.1.0 @@ -116,7 +116,7 @@ hb_ot_color_palette_get_name_id (hb_face_t *face, * @color_index: The index of the color * * Fetches the `name` table Name ID that provides display names for - * the specificed color in a face's `CPAL` color palette. + * the specified color in a face's `CPAL` color palette. * * Display names can be generic (e.g., "Background") or specific * (e.g., "Eye color"). @@ -256,6 +256,8 @@ hb_ot_color_has_svg (hb_face_t *face) * * Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded. * + * If the glyph has no SVG document, the singleton empty blob is returned. + * * Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available * * Since: 2.1.0 @@ -296,6 +298,8 @@ hb_ot_color_has_png (hb_face_t *face) * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font * object. If UPEM is unset, the blob returned will be the largest PNG available. * + * If the glyph has no PNG image, the singleton empty blob is returned. + * * Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available * * Since: 2.1.0 diff --git a/thirdparty/harfbuzz/src/hb-ot-deprecated.h b/thirdparty/harfbuzz/src/hb-ot-deprecated.h index ce6b6fef11..5192ff73e3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-deprecated.h +++ b/thirdparty/harfbuzz/src/hb-ot-deprecated.h @@ -50,6 +50,21 @@ HB_BEGIN_DECLS */ #define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER +/* https://github.com/harfbuzz/harfbuzz/pull/3417 */ +/** + * HB_OT_MATH_SCRIPT: + * + * Use #HB_SCRIPT_MATH or #HB_OT_TAG_MATH_SCRIPT instead. + * + * <note>Previous versions of this documentation recommended passing + * #HB_OT_MATH_SCRIPT to hb_buffer_set_script() to enable math shaping, but this + * usage is no longer supported. Use #HB_SCRIPT_MATH instead.</note> + * + * Since: 1.3.3 + * Deprecated: 3.4.0 + */ +#define HB_OT_MATH_SCRIPT HB_OT_TAG_MATH_SCRIPT + /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t diff --git a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh index eff09838af..c05034b3bb 100644 --- a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh +++ b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh @@ -32,6 +32,11 @@ #define HB_OT_FACE_TABLE_LIST_HH #endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */ +#ifndef HB_OT_CORE_TABLE +#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type) +#define _HB_OT_CORE_TABLE_UNDEF +#endif + #ifndef HB_OT_ACCELERATOR #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) #define _HB_OT_ACCELERATOR_UNDEF @@ -46,7 +51,8 @@ /* OpenType fundamentals. */ -HB_OT_TABLE (OT, head) +HB_OT_CORE_TABLE (OT, head) +HB_OT_CORE_TABLE (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif @@ -74,6 +80,7 @@ HB_OT_TABLE (OT, VORG) #endif /* TrueType outlines. */ +HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs HB_OT_ACCELERATOR (OT, glyf) /* CFF outlines. */ @@ -138,3 +145,7 @@ HB_OT_TABLE (OT, MATH) #ifdef _HB_OT_ACCELERATOR_UNDEF #undef HB_OT_ACCELERATOR #endif + +#ifdef _HB_OT_CORE_TABLE_UNDEF +#undef HB_OT_CORE_TABLE +#endif diff --git a/thirdparty/harfbuzz/src/hb-ot-face.hh b/thirdparty/harfbuzz/src/hb-ot-face.hh index e24d380bca..415dae8e20 100644 --- a/thirdparty/harfbuzz/src/hb-ot-face.hh +++ b/thirdparty/harfbuzz/src/hb-ot-face.hh @@ -63,10 +63,13 @@ struct hb_ot_face_t hb_face_t *face; /* MUST be JUST before the lazy loaders. */ #define HB_OT_TABLE(Namespace, Type) \ hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type; +#define HB_OT_CORE_TABLE(Namespace, Type) \ + hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type; #define HB_OT_ACCELERATOR(Namespace, Type) \ hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type; #include "hb-ot-face-table-list.hh" #undef HB_OT_ACCELERATOR +#undef HB_OT_CORE_TABLE #undef HB_OT_TABLE }; diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc index 9f0359a773..0f44ee4d5f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-font.cc +++ b/thirdparty/harfbuzz/src/hb-ot-font.cc @@ -131,11 +131,25 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - for (unsigned int i = 0; i < count; i++) + if (vmtx.has_data ()) + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } + else { - *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); - first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); - first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + hb_position_t advance = -(font_extents.ascender - font_extents.descender); + + for (unsigned int i = 0; i < count; i++) + { + *first_advance = advance; + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } } } #endif @@ -163,9 +177,19 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, hb_glyph_extents_t extents = {0}; if (ot_face->glyf->get_extents (font, glyph, &extents)) { - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t tsb = vmtx.get_side_bearing (font, glyph); - *y = extents.y_bearing + font->em_scale_y (tsb); + if (ot_face->vmtx->has_data ()) + { + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + hb_position_t tsb = vmtx.get_side_bearing (font, glyph); + *y = extents.y_bearing + font->em_scale_y (tsb); + return true; + } + + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + hb_position_t advance = font_extents.ascender - font_extents.descender; + int diff = advance - -extents.height; + *y = extents.y_bearing + (diff >> 1); return true; } @@ -257,6 +281,23 @@ hb_ot_get_font_v_extents (hb_font_t *font, } #endif +#ifndef HB_NO_DRAW +static void +hb_ot_get_glyph_shape (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data) +{ + hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + if (font->face->table.glyf->get_path (font, glyph, draw_session)) return; +#ifndef HB_NO_CFF + if (font->face->table.cff1->get_path (font, glyph, draw_session)) return; + if (font->face->table.cff2->get_path (font, glyph, draw_session)) return; +#endif +} +#endif + static inline void free_static_ot_funcs (); static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t> @@ -279,6 +320,10 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); #endif +#ifndef HB_NO_DRAW + hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr); +#endif + hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh index 6aa34295c7..866bb7e04c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh @@ -207,8 +207,7 @@ struct glyf _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const { - OT::glyf::accelerator_t glyf; - glyf.init (plan->source); + OT::glyf::accelerator_t glyf (plan->source); + hb_range (plan->num_output_glyphs ()) | hb_map ([&] (hb_codepoint_t new_gid) @@ -233,8 +232,6 @@ struct glyf }) | hb_sink (glyphs) ; - - glyf.fini (); } static bool @@ -595,7 +592,7 @@ struct glyf if (unlikely (!header.numberOfContours)) return; unsigned flags_offset = length (instructions_length ()); - if (unlikely (length (flags_offset + 1) > bytes.length)) return; + if (unlikely (flags_offset + 1 > bytes.length)) return; HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; @@ -823,8 +820,7 @@ struct glyf } #ifndef HB_NO_VAR - if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()))) - return false; + glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); #endif switch (type) { @@ -920,7 +916,7 @@ struct glyf struct accelerator_t { - void init (hb_face_t *face_) + accelerator_t (hb_face_t *face) { short_offset = false; num_glyphs = 0; @@ -933,14 +929,13 @@ struct glyf #ifndef HB_NO_VERTICAL vmtx = nullptr; #endif - face = face_; const OT::head &head = *face->table.head; if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; - loca_table = hb_sanitize_context_t ().reference_table<loca> (face); + loca_table = face->table.loca.get_blob (); // Needs no destruct! glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); #ifndef HB_NO_VAR gvar = face->table.gvar; @@ -953,13 +948,13 @@ struct glyf num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); } - - void fini () + ~accelerator_t () { - loca_table.destroy (); glyf_table.destroy (); } + bool has_data () const { return num_glyphs; } + protected: template<typename T> bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const @@ -1157,11 +1152,10 @@ struct glyf return operation_count; } -#ifdef HB_EXPERIMENTAL_API struct path_builder_t { hb_font_t *font; - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; struct optional_point_t { @@ -1176,10 +1170,10 @@ struct glyf { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } } first_oncurve, first_offcurve, last_offcurve; - path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) + path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { font = font_; - draw_helper = &draw_helper_; + draw_session = &draw_session_; first_oncurve = first_offcurve = last_offcurve = optional_point_t (); } @@ -1189,10 +1183,6 @@ struct glyf * https://stackoverflow.com/a/20772557 */ void consume_point (const contour_point_t &point) { - /* Skip empty contours */ - if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) - return; - bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; optional_point_t p (point.x, point.y); if (!first_oncurve.has_data) @@ -1200,7 +1190,7 @@ struct glyf if (is_on_curve) { first_oncurve = p; - draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); } else { @@ -1209,7 +1199,7 @@ struct glyf optional_point_t mid = first_offcurve.lerp (p, .5f); first_oncurve = mid; last_offcurve = p; - draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); } else first_offcurve = p; @@ -1221,22 +1211,22 @@ struct glyf { if (is_on_curve) { - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); last_offcurve = optional_point_t (); } else { optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); last_offcurve = p; } } else { if (is_on_curve) - draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); else last_offcurve = p; } @@ -1247,24 +1237,30 @@ struct glyf if (first_offcurve.has_data && last_offcurve.has_data) { optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); last_offcurve = optional_point_t (); /* now check the rest */ } if (first_offcurve.has_data && first_oncurve.has_data) - draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), - font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->quadratic_to (font->em_fscalef_x (first_offcurve.x), font->em_fscalef_y (first_offcurve.y), + font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); else if (last_offcurve.has_data && first_oncurve.has_data) - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); else if (first_oncurve.has_data) - draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->line_to (font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); + else if (first_offcurve.has_data) + { + float x = font->em_fscalef_x (first_offcurve.x), y = font->em_fscalef_x (first_offcurve.y); + draw_session->move_to (x, y); + draw_session->quadratic_to (x, y, x, y); + } /* Getting ready for the next contour */ first_oncurve = first_offcurve = last_offcurve = optional_point_t (); - draw_helper->end_path (); + draw_session->close_path (); } } void points_end () {} @@ -1274,9 +1270,8 @@ struct glyf }; bool - get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const - { return get_points (font, gid, path_builder_t (font, draw_helper)); } -#endif + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const + { return get_points (font, gid, path_builder_t (font, draw_session)); } #ifndef HB_NO_VAR const gvar_accelerator_t *gvar; @@ -1291,7 +1286,6 @@ struct glyf unsigned int num_glyphs; hb_blob_ptr_t<loca> loca_table; hb_blob_ptr_t<glyf> glyf_table; - hb_face_t *face; }; struct SubsetGlyph @@ -1358,7 +1352,10 @@ struct glyf * defining it _MIN instead. */ }; -struct glyf_accelerator_t : glyf::accelerator_t {}; +struct glyf_accelerator_t : glyf::accelerator_t { + glyf_accelerator_t (hb_face_t *face) : glyf::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh index 7d2d2d3eb8..d5e1fc91d2 100644 --- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh @@ -28,6 +28,7 @@ #define HB_OT_HMTX_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-var-hvar-table.hh" #include "hb-ot-metrics.hh" @@ -98,12 +99,12 @@ struct hmtxvmtx hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it, - unsigned num_advances) + unsigned num_long_metrics) { unsigned idx = 0; for (auto _ : it) { - if (idx < num_advances) + if (idx < num_long_metrics) { LongMetric lm; lm.advance = _.first; @@ -127,9 +128,20 @@ struct hmtxvmtx T *table_prime = c->serializer->start_embed <T> (); if (unlikely (!table_prime)) return_trace (false); - accelerator_t _mtx; - _mtx.init (c->plan->source); - unsigned num_advances = _mtx.num_advances_for_subset (c->plan); + accelerator_t _mtx (c->plan->source); + unsigned num_long_metrics; + { + /* Determine num_long_metrics to encode. */ + auto& plan = c->plan; + num_long_metrics = plan->num_output_glyphs (); + hb_codepoint_t old_gid = 0; + unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0; + while (num_long_metrics > 1 && + last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0)) + { + num_long_metrics--; + } + } auto it = + hb_range (c->plan->num_output_glyphs ()) @@ -142,15 +154,13 @@ struct hmtxvmtx }) ; - table_prime->serialize (c->serializer, it, num_advances); - - _mtx.fini (); + table_prime->serialize (c->serializer, it, num_long_metrics); if (unlikely (c->serializer->in_error ())) return_trace (false); // Amend header num hmetrics - if (unlikely (!subset_update_header (c->plan, num_advances))) + if (unlikely (!subset_update_header (c->plan, num_long_metrics))) return_trace (false); return_trace (true); @@ -160,56 +170,67 @@ struct hmtxvmtx { friend struct hmtxvmtx; - void init (hb_face_t *face, - unsigned int default_advance_ = 0) + accelerator_t (hb_face_t *face) { - default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); + table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); + var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag); + + default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face); + + /* Populate count variables and sort them out as we go */ - num_advances = T::is_horizontal ? - face->table.hhea->numberOfLongMetrics : + unsigned int len = table.get_length (); + if (len & 1) + len--; + + num_long_metrics = T::is_horizontal ? + face->table.hhea->numberOfLongMetrics : #ifndef HB_NO_VERTICAL - face->table.vhea->numberOfLongMetrics + face->table.vhea->numberOfLongMetrics #else - 0 + 0 #endif - ; + ; + if (unlikely (num_long_metrics * 4 > len)) + num_long_metrics = len / 4; + len -= num_long_metrics * 4; - table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); + num_bearings = face->table.maxp->get_num_glyphs (); - /* Cap num_metrics() and num_advances() based on table length. */ - unsigned int len = table.get_length (); - if (unlikely (num_advances * 4 > len)) - num_advances = len / 4; - num_metrics = num_advances + (len - 4 * num_advances) / 2; + if (unlikely (num_bearings < num_long_metrics)) + num_bearings = num_long_metrics; + if (unlikely ((num_bearings - num_long_metrics) * 2 > len)) + num_bearings = num_long_metrics + len / 2; + len -= (num_bearings - num_long_metrics) * 2; - /* We MUST set num_metrics to zero if num_advances is zero. + /* We MUST set num_bearings to zero if num_long_metrics is zero. * Our get_advance() depends on that. */ - if (unlikely (!num_advances)) - { - num_metrics = num_advances = 0; - table.destroy (); - table = hb_blob_get_empty (); - } + if (unlikely (!num_long_metrics)) + num_bearings = num_long_metrics = 0; - var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag); + num_advances = num_bearings + len / 2; + num_glyphs = face->get_num_glyphs (); + if (num_glyphs < num_advances) + num_glyphs = num_advances; } - - void fini () + ~accelerator_t () { table.destroy (); var_table.destroy (); } + bool has_data () const { return (bool) num_bearings; } + int get_side_bearing (hb_codepoint_t glyph) const { - if (glyph < num_advances) + if (glyph < num_long_metrics) return table->longMetricZ[glyph].sb; - if (unlikely (glyph >= num_metrics)) + if (unlikely (glyph >= num_bearings)) return 0; - const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; - return bearings[glyph - num_advances]; + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; + return bearings[glyph - num_long_metrics]; } int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const @@ -217,7 +238,7 @@ struct hmtxvmtx int side_bearing = get_side_bearing (glyph); #ifndef HB_NO_VAR - if (unlikely (glyph >= num_metrics) || !font->num_coords) + if (unlikely (glyph >= num_bearings) || !font->num_coords) return side_bearing; if (var_table.get_length ()) @@ -231,18 +252,35 @@ struct hmtxvmtx unsigned int get_advance (hb_codepoint_t glyph) const { - if (unlikely (glyph >= num_metrics)) - { - /* If num_metrics is zero, it means we don't have the metrics table - * for this direction: return default advance. Otherwise, it means that the - * glyph index is out of bound: return zero. */ - if (num_metrics) - return 0; - else - return default_advance; - } + /* OpenType case. */ + if (glyph < num_bearings) + return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance; + + /* If num_advances is zero, it means we don't have the metrics table + * for this direction: return default advance. Otherwise, there's a + * well-defined answer. */ + if (unlikely (!num_advances)) + return default_advance; - return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance; +#ifdef HB_NO_BORING_EXPANSION + return 0; +#endif + + if (unlikely (glyph >= num_glyphs)) + return 0; + + /* num_bearings <= glyph < num_glyphs; + * num_bearings <= num_advances */ + + /* TODO Optimize */ + + if (num_bearings == num_advances) + return get_advance (num_bearings - 1); + + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; + const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; + + return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; } unsigned int get_advance (hb_codepoint_t glyph, @@ -251,7 +289,7 @@ struct hmtxvmtx unsigned int advance = get_advance (glyph); #ifndef HB_NO_VAR - if (unlikely (glyph >= num_metrics) || !font->num_coords) + if (unlikely (glyph >= num_bearings) || !font->num_coords) return advance; if (var_table.get_length ()) @@ -263,35 +301,13 @@ struct hmtxvmtx #endif } - unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const - { - unsigned int num_advances = plan->num_output_glyphs (); - unsigned int last_advance = _advance_for_new_gid (plan, - num_advances - 1); - while (num_advances > 1 && - last_advance == _advance_for_new_gid (plan, - num_advances - 2)) - { - num_advances--; - } - - return num_advances; - } - - private: - unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, - hb_codepoint_t new_gid) const - { - hb_codepoint_t old_gid; - if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) - return 0; - - return get_advance (old_gid); - } - protected: - unsigned int num_metrics; - unsigned int num_advances; + // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs + unsigned num_long_metrics; + unsigned num_bearings; + unsigned num_advances; + unsigned num_glyphs; + unsigned int default_advance; private: @@ -323,6 +339,8 @@ struct hmtxvmtx * the end. This allows a monospaced * font to vary the side bearing * values for each glyph. */ +/*UnsizedArrayOf<UFWORD>advancesX;*/ + /* TODO Document. */ public: DEFINE_SIZE_ARRAY (0, longMetricZ); }; @@ -338,8 +356,12 @@ struct vmtx : hmtxvmtx<vmtx, vhea> { static constexpr bool is_horizontal = false; }; -struct hmtx_accelerator_t : hmtx::accelerator_t {}; -struct vmtx_accelerator_t : vmtx::accelerator_t {}; +struct hmtx_accelerator_t : hmtx::accelerator_t { + hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} +}; +struct vmtx_accelerator_t : vmtx::accelerator_t { + vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh index eb4c3b46e2..1b9dfcd3f5 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh @@ -41,7 +41,10 @@ namespace OT { struct BaseCoordFormat1 { - hb_position_t get_coord () const { return coordinate; } + hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -58,10 +61,10 @@ struct BaseCoordFormat1 struct BaseCoordFormat2 { - hb_position_t get_coord () const + hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const { /* TODO */ - return coordinate; + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); } bool sanitize (hb_sanitize_context_t *c) const @@ -87,9 +90,10 @@ struct BaseCoordFormat3 hb_direction_t direction) const { const Device &device = this+deviceTable; - return coordinate + (HB_DIRECTION_IS_VERTICAL (direction) ? - device.get_y_delta (font, var_store) : - device.get_x_delta (font, var_store)); + + return HB_DIRECTION_IS_HORIZONTAL (direction) + ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store) + : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store); } @@ -120,8 +124,8 @@ struct BaseCoord hb_direction_t direction) const { switch (u.format) { - case 1: return u.format1.get_coord (); - case 2: return u.format2.get_coord (); + case 1: return u.format1.get_coord (font, direction); + case 2: return u.format2.get_coord (font, direction); case 3: return u.format3.get_coord (font, var_store, direction); default:return 0; } diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index 4fb1893435..b644df708d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -37,7 +37,7 @@ #ifndef HB_MAX_NESTING_LEVEL -#define HB_MAX_NESTING_LEVEL 6 +#define HB_MAX_NESTING_LEVEL 64 #endif #ifndef HB_MAX_CONTEXT_LENGTH #define HB_MAX_CONTEXT_LENGTH 64 @@ -60,6 +60,10 @@ #define HB_MAX_LANGSYS 2000 #endif +#ifndef HB_MAX_LANGSYS_FEATURE_COUNT +#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 +#endif + #ifndef HB_MAX_FEATURES #define HB_MAX_FEATURES 750 #endif @@ -87,12 +91,12 @@ template<typename Iterator> static inline void ClassDef_serialize (hb_serialize_context_t *c, Iterator it); -static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t<HBGlyphID16> &glyphs, - const hb_set_t &klasses, - bool use_class_zero, - hb_map_t *klass_map /*INOUT*/); +static void ClassDef_remap_and_serialize ( + hb_serialize_context_t *c, + const hb_set_t &klasses, + bool use_class_zero, + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/); struct hb_prune_langsys_context_t @@ -105,34 +109,15 @@ struct hb_prune_langsys_context_t script_langsys_map (script_langsys_map_), duplicate_feature_map (duplicate_feature_map_), new_feature_indexes (new_collected_feature_indexes_), - script_count (0),langsys_count (0) {} - - bool visitedScript (const void *s) - { - if (script_count++ > HB_MAX_SCRIPTS) - return true; - - return visited (s, visited_script); - } - - bool visitedLangsys (const void *l) - { - if (langsys_count++ > HB_MAX_LANGSYS) - return true; + script_count (0),langsys_feature_count (0) {} - return visited (l, visited_langsys); - } + bool visitScript () + { return script_count++ < HB_MAX_SCRIPTS; } - private: - template <typename T> - bool visited (const T *p, hb_set_t &visited_set) + bool visitLangsys (unsigned feature_count) { - hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table); - if (visited_set.has (delta)) - return true; - - visited_set.add (delta); - return false; + langsys_feature_count += feature_count; + return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT; } public: @@ -142,10 +127,8 @@ struct hb_prune_langsys_context_t hb_set_t *new_feature_indexes; private: - hb_set_t visited_script; - hb_set_t visited_langsys; unsigned script_count; - unsigned langsys_count; + unsigned langsys_feature_count; }; struct hb_subset_layout_context_t : @@ -643,11 +626,14 @@ struct LangSys | hb_map (feature_index_map) ; - if (iter.len () != o_iter.len ()) - return false; + for (; iter && o_iter; iter++, o_iter++) + { + unsigned a = *iter; + unsigned b = *o_iter; + if (a != b) return false; + } - for (const auto _ : + hb_zip (iter, o_iter)) - if (_.first != _.second) return false; + if (iter || o_iter) return false; return true; } @@ -655,7 +641,6 @@ struct LangSys void collect_features (hb_prune_langsys_context_t *c) const { if (!has_required_feature () && !get_feature_count ()) return; - if (c->visitedLangsys (this)) return; if (has_required_feature () && c->duplicate_feature_map->has (reqFeatureIndex)) c->new_feature_indexes->add (get_required_feature_index ()); @@ -733,7 +718,7 @@ struct Script unsigned script_index) const { if (!has_default_lang_sys () && !get_lang_sys_count ()) return; - if (c->visitedScript (this)) return; + if (!c->visitScript ()) return; if (!c->script_langsys_map->has (script_index)) { @@ -750,11 +735,14 @@ struct Script { //only collect features from non-redundant langsys const LangSys& d = get_default_lang_sys (); - d.collect_features (c); + if (c->visitLangsys (d.get_feature_count ())) { + d.collect_features (c); + } for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) { const LangSys& l = this+_.first.offset; + if (!c->visitLangsys (l.get_feature_count ())) continue; if (l.compare (d, c->duplicate_feature_map)) continue; l.collect_features (c); @@ -766,6 +754,7 @@ struct Script for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) { const LangSys& l = this+_.first.offset; + if (!c->visitLangsys (l.get_feature_count ())) continue; l.collect_features (c); c->script_langsys_map->get (script_index)->add (_.second); } @@ -845,7 +834,7 @@ struct FeatureParamsSize if (unlikely (!c->check_struct (this))) return_trace (false); /* This subtable has some "history", if you will. Some earlier versions of - * Adobe tools calculated the offset of the FeatureParams sutable from the + * 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. @@ -1481,7 +1470,8 @@ struct CoverageFormat1 void next () { i++; } hb_codepoint_t get_glyph () const { return c->glyphArray[i]; } bool operator != (const iter_t& o) const - { return i != o.i || c != o.c; } + { return i != o.i; } + iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; } private: const struct CoverageFormat1 *c; @@ -1517,12 +1507,6 @@ struct CoverageFormat2 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!glyphs)) - { - rangeRecord.len = 0; - return_trace (true); - } - /* TODO(iter) Write more efficiently? */ unsigned num_ranges = 0; @@ -1535,6 +1519,7 @@ struct CoverageFormat2 } if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false); + if (!num_ranges) return_trace (true); unsigned count = 0; unsigned range = (unsigned) -1; @@ -1563,25 +1548,26 @@ struct CoverageFormat2 bool intersects (const hb_set_t *glyphs) const { - /* TODO Speed up, using hb_set_next() and bsearch()? */ - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) - if (range.intersects (glyphs)) - return true; - return false; + return hb_any (+ hb_iter (rangeRecord.as_array ()) + | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) + auto cmp = [] (const void *pk, const void *pr) -> int { - if (range.value <= index && - index < (unsigned int) range.value + (range.last - range.first) && - range.intersects (glyphs)) - return true; - else if (index < range.value) - return false; - } + unsigned index = * (const unsigned *) pk; + const RangeRecord &range = * (const RangeRecord *) pr; + if (index < range.value) return -1; + if (index > (unsigned int) range.value + (range.last - range.first)) return +1; + return 0; + }; + + auto arr = rangeRecord.as_array (); + unsigned idx; + if (hb_bsearch_impl (&idx, index, + arr.arrayZ, arr.length, sizeof (arr[0]), + (int (*)(const void *_key, const void *_item)) cmp)) + return arr.arrayZ[idx].intersects (glyphs); return false; } @@ -1590,8 +1576,10 @@ struct CoverageFormat2 for (const auto& range : rangeRecord.as_array ()) { if (!range.intersects (glyphs)) continue; - for (hb_codepoint_t g = range.first; g <= range.last; g++) - if (glyphs->has (g)) intersect_glyphs->add (g); + unsigned last = range.last; + for (hb_codepoint_t g = range.first - 1; + glyphs->next (&g) && g <= last;) + intersect_glyphs->add (g); } } @@ -1643,6 +1631,8 @@ struct CoverageFormat2 return; } } + else + j = 0; return; } coverage++; @@ -1650,7 +1640,15 @@ struct CoverageFormat2 } hb_codepoint_t get_glyph () const { return j; } bool operator != (const iter_t& o) const - { return i != o.i || j != o.j || c != o.c; } + { return i != o.i || j != o.j; } + iter_t __end__ () const + { + iter_t it; + it.init (*c); + it.i = c->rangeRecord.len; + it.j = 0; + return it; + } private: const struct CoverageFormat2 *c; @@ -1719,18 +1717,17 @@ struct Coverage bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - auto it = + iter () - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) + | hb_filter (c->plan->glyph_map_gsub) + | hb_map_retains_sorting (c->plan->glyph_map_gsub) ; - bool ret = bool (it); - Coverage_serialize (c->serializer, it); - return_trace (ret); + // Cache the iterator result as it will be iterated multiple times + // by the serialize code below. + hb_sorted_vector_t<hb_codepoint_t> glyphs (it); + Coverage_serialize (c->serializer, glyphs.iter ()); + return_trace (bool (glyphs)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1833,7 +1830,7 @@ struct Coverage } bool operator != (const iter_t& o) const { - if (format != o.format) return true; + if (unlikely (format != o.format)) return true; switch (format) { case 1: return u.format1 != o.u.format1; @@ -1841,6 +1838,18 @@ struct Coverage default:return false; } } + iter_t __end__ () const + { + iter_t it = {}; + it.format = format; + switch (format) + { + case 1: it.u.format1 = u.format1.__end__ (); break; + case 2: it.u.format2 = u.format2.__end__ (); break; + default: break; + } + return it; + } private: unsigned int format; @@ -1868,16 +1877,14 @@ Coverage_serialize (hb_serialize_context_t *c, { c->start_embed<Coverage> ()->serialize (c, it); } static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t<HBGlyphID16> &glyphs, const hb_set_t &klasses, bool use_class_zero, - hb_map_t *klass_map /*INOUT*/) + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/) { if (!klass_map) { - ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter () - | hb_map (gid_klass_map))); + ClassDef_serialize (c, glyph_and_klass.iter ()); return; } @@ -1894,17 +1901,15 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, idx++; } - auto it = - + glyphs.iter () - | hb_map_retains_sorting ([&] (const HBGlyphID16& gid) -> hb_pair_t<hb_codepoint_t, unsigned> - { - unsigned new_klass = klass_map->get (gid_klass_map[gid]); - return hb_pair ((hb_codepoint_t)gid, new_klass); - }) - ; - c->propagate_error (glyphs, klasses); - ClassDef_serialize (c, it); + 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); + } + + c->propagate_error (glyph_and_klass, klasses); + ClassDef_serialize (c, glyph_and_klass.iter ()); } /* @@ -1960,36 +1965,37 @@ struct ClassDefFormat1 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t<HBGlyphID16> glyphs; + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; hb_codepoint_t start = startGlyph; hb_codepoint_t end = start + classValue.len; - for (const hb_codepoint_t gid : + hb_range (start, end) - | hb_filter (glyphset)) + for (const hb_codepoint_t gid : + hb_range (start, end)) { + hb_codepoint_t new_gid = glyph_map[gid]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has(gid)) continue; unsigned klass = classValue[gid - start]; if (!klass) continue; - glyphs.push (glyph_map[gid]); - gid_org_klass_map.set (glyph_map[gid], klass); + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } unsigned glyph_count = glyph_filter - ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -2055,10 +2061,9 @@ struct ClassDefFormat1 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const HBUINT16 *arr = classValue.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i] == k && glyphs->has (startGlyph + i)) + if (arr[i] == klass && glyphs->has (startGlyph + i)) return true; return false; } @@ -2068,17 +2073,32 @@ struct ClassDefFormat1 unsigned count = classValue.len; if (klass == 0) { - hb_codepoint_t endGlyph = startGlyph + count -1; - for (hb_codepoint_t g : glyphs->iter ()) - if (g < startGlyph || g > endGlyph) - intersect_glyphs->add (g); + unsigned start_glyph = startGlyph; + for (unsigned g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g) && g < start_glyph;) + intersect_glyphs->add (g); + + for (unsigned g = startGlyph + count - 1; + hb_set_next (glyphs, &g);) + intersect_glyphs->add (g); return; } for (unsigned i = 0; i < count; i++) if (classValue[i] == klass && glyphs->has (startGlyph + i)) - intersect_glyphs->add (startGlyph + i); + intersect_glyphs->add (startGlyph + i); + +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + unsigned start_glyph = startGlyph; + unsigned end_glyph = start_glyph + count; + for (unsigned g = startGlyph - 1; + hb_set_next (glyphs, &g) && g < end_glyph;) + if (classValue.arrayZ[g - start_glyph] == klass) + intersect_glyphs->add (g); +#endif } void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const @@ -2178,12 +2198,10 @@ struct ClassDefFormat2 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t<HBGlyphID16> glyphs; + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; unsigned count = rangeRecord.len; for (unsigned i = 0; i < count; i++) @@ -2194,21 +2212,26 @@ struct ClassDefFormat2 hb_codepoint_t end = rangeRecord[i].last + 1; for (hb_codepoint_t g = start; g < end; g++) { - if (!glyphset.has (g)) continue; + hb_codepoint_t new_gid = glyph_map[g]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has (g)) continue; - glyphs.push (glyph_map[g]); - gid_org_klass_map.set (glyph_map[g], klass); + + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } } + const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -2274,10 +2297,9 @@ struct ClassDefFormat2 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const RangeRecord *arr = rangeRecord.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i].value == k && arr[i].intersects (glyphs)) + if (arr[i].value == klass && arr[i].intersects (glyphs)) return true; return false; } @@ -2290,43 +2312,44 @@ struct ClassDefFormat2 hb_codepoint_t g = HB_SET_VALUE_INVALID; for (unsigned int i = 0; i < count; i++) { - if (!hb_set_next (glyphs, &g)) - break; - while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first) - { - intersect_glyphs->add (g); - hb_set_next (glyphs, &g); + if (!hb_set_next (glyphs, &g)) + goto done; + while (g < rangeRecord[i].first) + { + intersect_glyphs->add (g); + if (!hb_set_next (glyphs, &g)) + goto done; } g = rangeRecord[i].last; } - while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) - intersect_glyphs->add (g); + while (hb_set_next (glyphs, &g)) + intersect_glyphs->add (g); + done: return; } - hb_codepoint_t g = HB_SET_VALUE_INVALID; +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + if ((count >> 3) > glyphs->get_population ()) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g);) + if (rangeRecord.as_array ().bfind (g)) + intersect_glyphs->add (g); + return; + } +#endif + for (unsigned int i = 0; i < count; i++) { if (rangeRecord[i].value != klass) continue; - if (g != HB_SET_VALUE_INVALID) - { - if (g >= rangeRecord[i].first && - g <= rangeRecord[i].last) - intersect_glyphs->add (g); - if (g > rangeRecord[i].last) - continue; - } - - g = rangeRecord[i].first - 1; - while (hb_set_next (glyphs, &g)) - { - if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) - intersect_glyphs->add (g); - else if (g > rangeRecord[i].last) - break; - } + unsigned end = rangeRecord[i].last + 1; + for (hb_codepoint_t g = rangeRecord[i].first - 1; + hb_set_next (glyphs, &g) && g < end;) + intersect_glyphs->add (g); } } @@ -2926,8 +2949,6 @@ struct VariationStore hb_vector_t<hb_inc_bimap_t> inner_maps; inner_maps.resize ((unsigned) dataSets.len); - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].init (); for (unsigned idx : c->plan->layout_variation_indices->iter ()) { @@ -2935,18 +2956,11 @@ struct VariationStore uint16_t minor = idx & 0xFFFF; if (major >= inner_maps.length) - { - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].fini (); return_trace (false); - } inner_maps[major].add (minor); } varstore_prime->serialize (c->serializer, this, inner_maps.as_array ()); - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].fini (); - return_trace ( !c->serializer->in_error() && varstore_prime->dataSets); diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh index aea644f3e1..a76d644c4b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh @@ -585,17 +585,16 @@ struct GDEF struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { - this->table = hb_sanitize_context_t ().reference_table<GDEF> (face); - if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) + table = hb_sanitize_context_t ().reference_table<GDEF> (face); + if (unlikely (table->is_blocklisted (table.get_blob (), face))) { - hb_blob_destroy (this->table.get_blob ()); - this->table = hb_blob_get_empty (); + hb_blob_destroy (table.get_blob ()); + table = hb_blob_get_empty (); } } - - void fini () { this->table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_ptr_t<GDEF> table; }; @@ -715,7 +714,9 @@ struct GDEF DEFINE_SIZE_MIN (12); }; -struct GDEF_accelerator_t : GDEF::accelerator_t {}; +struct GDEF_accelerator_t : GDEF::accelerator_t { + GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh index 6db3e08940..2f9186a2a7 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh @@ -706,7 +706,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage or float mark_x, mark_y, base_x, base_y; - buffer->unsafe_to_break (glyph_pos, buffer->idx); + buffer->unsafe_to_break (glyph_pos, buffer->idx + 1); mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); @@ -1235,6 +1235,7 @@ struct PairSet buffer->idx = pos; return_trace (true); } + buffer->unsafe_to_concat (buffer->idx, pos + 1); return_trace (false); } @@ -1362,7 +1363,12 @@ struct PairPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); } @@ -1555,7 +1561,12 @@ struct PairPosFormat2 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); @@ -1563,13 +1574,89 @@ struct PairPosFormat2 unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); - if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) + { + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + return_trace (false); + } const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - bool applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - bool applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + bool applied_first = false, applied_second = false; + + + /* Isolate simple kerning and apply it half to each side. + * Results in better cursor positinoing / underline drawing. + * + * Disabled, because causes issues... :-( + * https://github.com/harfbuzz/harfbuzz/issues/3408 + * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 + */ +#ifndef HB_SPLIT_KERN + if (0) +#endif + { + if (!len2) + { + const hb_direction_t dir = buffer->props.direction; + const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir); + const bool backward = HB_DIRECTION_IS_BACKWARD (dir); + unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance; + if (backward) + mask |= mask >> 2; /* Add eg. xPlacement in RTL. */ + /* Add Devices. */ + mask |= mask << 4; + + if (valueFormat1 & ~mask) + goto bail; + + /* Is simple kern. Apply value on an empty position slot, + * then split it between sides. */ + + hb_glyph_position_t pos{}; + if (valueFormat1.apply_value (c, this, v, pos)) + { + hb_position_t *src = &pos.x_advance; + hb_position_t *dst1 = &buffer->cur_pos().x_advance; + hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance; + unsigned i = horizontal ? 0 : 1; + + hb_position_t kern = src[i]; + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + + if (!backward) + { + dst1[i] += kern1; + dst2[i] += kern2; + dst2[i + 2] += kern2; + } + else + { + dst1[i] += kern1; + dst1[i + 2] += src[i + 2] - kern2; + dst2[i] += kern2; + } + + applied_first = applied_second = kern != 0; + goto success; + } + goto boring; + } + } + bail: + + + applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + success: if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + else + boring: + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + buffer->idx = skippy_iter.idx; if (len2) @@ -1799,10 +1886,19 @@ struct CursivePosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) return_trace (false); + if (!prev_record.exitAnchor) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } unsigned int i = skippy_iter.idx; unsigned int j = buffer->idx; @@ -2066,7 +2162,13 @@ struct MarkBasePosFormat1 skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); do { - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + /* We only want to attach to the first of a MultipleSubst sequence. * https://github.com/harfbuzz/harfbuzz/issues/740 * Reject others... @@ -2089,7 +2191,11 @@ struct MarkBasePosFormat1 //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); - if (base_index == NOT_COVERED) return_trace (false); + if (base_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } @@ -2320,21 +2426,34 @@ struct MarkLigPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); - if (lig_index == NOT_COVERED) return_trace (false); + if (lig_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } const LigatureArray& lig_array = this+ligatureArray; const LigatureAttach& lig_attach = lig_array[lig_index]; /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; - if (unlikely (!comp_count)) return_trace (false); + if (unlikely (!comp_count)) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } /* We must now check whether the ligature ID of the current mark glyph * is identical to the ligature ID of the found ligature. If yes, we @@ -2517,9 +2636,18 @@ struct MarkMarkPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); } + if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } unsigned int j = skippy_iter.idx; @@ -2544,11 +2672,16 @@ struct MarkMarkPosFormat1 } /* Didn't match. */ + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); good: unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); - if (mark2_index == NOT_COVERED) return_trace (false); + if (mark2_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } @@ -2951,7 +3084,7 @@ GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer H } void -GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) +GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { _hb_buffer_assert_gsubgpos_vars (buffer); @@ -2961,12 +3094,21 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) - for (unsigned int i = 0; i < len; i++) + for (unsigned i = 0; i < len; i++) propagate_attachment_offsets (pos, len, i, direction); + + if (unlikely (font->slant)) + { + for (unsigned i = 0; i < len; i++) + if (unlikely (pos[i].y_offset)) + pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); + } } -struct GPOS_accelerator_t : GPOS::accelerator_t {}; +struct GPOS_accelerator_t : GPOS::accelerator_t { + GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {} +}; /* Out-of-class implementation for methods recursing */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh index b7ce30135e..bef381430b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh @@ -29,1719 +29,14 @@ #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH #define HB_OT_LAYOUT_GSUB_TABLE_HH -#include "hb-ot-layout-gsubgpos.hh" - +#include "OT/Layout/GSUB/GSUB.hh" namespace OT { -typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; - -template<typename Iterator> -static void SingleSubst_serialize (hb_serialize_context_t *c, - Iterator it); - - -struct SingleSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - bool may_have_non_1to1 () const - { return false; } - - void closure (hb_closure_context_t *c) const - { - unsigned d = deltaGlyphID; - - + hb_iter (this+coverage) - | hb_filter (c->parent_active_glyphs ()) - | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) - | hb_sink (c->output) - ; - - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - unsigned d = deltaGlyphID; - + hb_iter (this+coverage) - | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) - | hb_sink (c->output) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return_trace (false); - - /* According to the Adobe Annotated OpenType Suite, result is always - * limited to 16bit. */ - glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; - c->replace_glyph (glyph_id); - - return_trace (true); - } - - template<typename Iterator, - hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))> - bool serialize (hb_serialize_context_t *c, - Iterator glyphs, - unsigned delta) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false); - c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW); - return_trace (true); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - hb_codepoint_t delta = deltaGlyphID; - - auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) - | hb_map_retains_sorting ([&] (hb_codepoint_t g) { - return hb_codepoint_pair_t (g, - (g + delta) & 0xFFFF); }) - | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t - { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) - ; - - bool ret = bool (it); - SingleSubst_serialize (c->serializer, it); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - HBUINT16 deltaGlyphID; /* Add to original GlyphID to get - * substitute GlyphID, modulo 0x10000 */ - public: - DEFINE_SIZE_STATIC (6); -}; - -struct SingleSubstFormat2 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - bool may_have_non_1to1 () const - { return false; } - - void closure (hb_closure_context_t *c) const - { - + hb_zip (this+coverage, substitute) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_sink (c->output) - ; - - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - + hb_zip (this+coverage, substitute) - | hb_map (hb_second) - | hb_sink (c->output) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - if (unlikely (index >= substitute.len)) return_trace (false); - - c->replace_glyph (substitute[index]); - - return_trace (true); - } - - template<typename Iterator, - hb_requires (hb_is_sorted_source_of (Iterator, - hb_codepoint_pair_t))> - bool serialize (hb_serialize_context_t *c, - Iterator it) - { - TRACE_SERIALIZE (this); - auto substitutes = - + it - | hb_map (hb_second) - ; - auto glyphs = - + it - | hb_map_retains_sorting (hb_first) - ; - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false); - if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false); - return_trace (true); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto it = - + hb_zip (this+coverage, substitute) - | hb_filter (glyphset, hb_first) - | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t - { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) - ; - - bool ret = bool (it); - SingleSubst_serialize (c->serializer, it); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - Array16Of<HBGlyphID16> - substitute; /* Array of substitute - * GlyphIDs--ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (6, substitute); -}; - -struct SingleSubst -{ - - template<typename Iterator, - hb_requires (hb_is_sorted_source_of (Iterator, - const hb_codepoint_pair_t))> - bool serialize (hb_serialize_context_t *c, - Iterator glyphs) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned format = 2; - unsigned delta = 0; - if (glyphs) - { - format = 1; - auto get_delta = [=] (hb_codepoint_pair_t _) - { return (unsigned) (_.second - _.first) & 0xFFFF; }; - delta = get_delta (*glyphs); - if (!hb_all (++(+glyphs), delta, get_delta)) format = 2; - } - u.format = format; - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, - + glyphs - | hb_map_retains_sorting (hb_first), - delta)); - case 2: return_trace (u.format2.serialize (c, glyphs)); - default:return_trace (false); - } - } - - 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, std::forward<Ts> (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - SingleSubstFormat1 format1; - SingleSubstFormat2 format2; - } u; -}; - -template<typename Iterator> -static void -SingleSubst_serialize (hb_serialize_context_t *c, - Iterator it) -{ c->start_embed<SingleSubst> ()->serialize (c, it); } - -struct Sequence -{ - bool intersects (const hb_set_t *glyphs) const - { return hb_all (substitute, glyphs); } - - void closure (hb_closure_context_t *c) const - { c->output->add_array (substitute.arrayZ, substitute.len); } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { c->output->add_array (substitute.arrayZ, substitute.len); } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int count = substitute.len; - - /* Special-case to make it in-place and not consider this - * as a "multiplied" substitution. */ - if (unlikely (count == 1)) - { - c->replace_glyph (substitute.arrayZ[0]); - return_trace (true); - } - /* Spec disallows this, but Uniscribe allows it. - * https://github.com/harfbuzz/harfbuzz/issues/253 */ - else if (unlikely (count == 0)) - { - c->buffer->delete_glyph (); - return_trace (true); - } - - unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? - HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; - unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur()); - - for (unsigned int i = 0; i < count; i++) - { - /* If is attached to a ligature, don't disturb that. - * https://github.com/harfbuzz/harfbuzz/issues/3069 */ - if (!lig_id) - _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); - c->output_glyph_for_component (substitute.arrayZ[i], klass); - } - c->buffer->skip_glyph (); - - return_trace (true); - } - - template <typename Iterator, - hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> - bool serialize (hb_serialize_context_t *c, - Iterator subst) - { - TRACE_SERIALIZE (this); - return_trace (substitute.serialize (c, subst)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - if (!intersects (&glyphset)) return_trace (false); - - auto it = - + hb_iter (substitute) - | hb_map (glyph_map) - ; - - auto *out = c->serializer->start_embed (*this); - return_trace (out->serialize (c->serializer, it)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (substitute.sanitize (c)); - } - - protected: - Array16Of<HBGlyphID16> - substitute; /* String of GlyphIDs to substitute */ - public: - DEFINE_SIZE_ARRAY (2, substitute); -}; - -struct MultipleSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - bool may_have_non_1to1 () const - { return true; } - - void closure (hb_closure_context_t *c) const - { - + hb_zip (this+coverage, sequence) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Sequence &_) { _.closure (c); }) - ; - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - + hb_zip (this+coverage, sequence) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); }) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - - unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - return_trace ((this+sequence[index]).apply (c)); - } - - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < glyphs.length; i++) - { - unsigned int substitute_len = substitute_len_list[i]; - if (unlikely (!sequence[i] - .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len)))) - return_trace (false); - substitute_glyphs_list += substitute_len; - } - return_trace (coverage.serialize_serialize (c, glyphs)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - 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; - - hb_sorted_vector_t<hb_codepoint_t> new_coverage; - + hb_zip (this+coverage, sequence) - | hb_filter (glyphset, hb_first) - | hb_filter (subset_offset_array (c, out->sequence, this), hb_second) - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); - return_trace (bool (new_coverage)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - Array16OfOffset16To<Sequence> - sequence; /* Array of Sequence tables - * ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (6, sequence); -}; - -struct MultipleSubst -{ - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 1; - u.format = format; - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); - default:return_trace (false); - } - } - - 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, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - MultipleSubstFormat1 format1; - } u; -}; - -struct AlternateSet -{ - bool intersects (const hb_set_t *glyphs) const - { return hb_any (alternates, glyphs); } - - void closure (hb_closure_context_t *c) const - { c->output->add_array (alternates.arrayZ, alternates.len); } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { c->output->add_array (alternates.arrayZ, alternates.len); } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int count = alternates.len; - - if (unlikely (!count)) return_trace (false); - - hb_mask_t glyph_mask = c->buffer->cur().mask; - hb_mask_t lookup_mask = c->lookup_mask; - - /* Note: This breaks badly if two features enabled this lookup together. */ - unsigned int shift = hb_ctz (lookup_mask); - unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - - /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */ - if (alt_index == HB_OT_MAP_MAX_VALUE && c->random) - { - /* Maybe we can do better than unsafe-to-break all; but since we are - * changing random state, it would be hard to track that. Good 'nough. */ - c->buffer->unsafe_to_break (0, c->buffer->len); - alt_index = c->random_number () % count + 1; - } - - if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); - - c->replace_glyph (alternates[alt_index - 1]); - - return_trace (true); - } - - unsigned - get_alternates (unsigned start_offset, - unsigned *alternate_count /* IN/OUT. May be NULL. */, - hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const - { - if (alternates.len && alternate_count) - { - + alternates.sub_array (start_offset, alternate_count) - | hb_sink (hb_array (alternate_glyphs, *alternate_count)) - ; - } - return alternates.len; - } - - template <typename Iterator, - hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> - bool serialize (hb_serialize_context_t *c, - Iterator alts) - { - TRACE_SERIALIZE (this); - return_trace (alternates.serialize (c, alts)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto it = - + hb_iter (alternates) - | hb_filter (glyphset) - | hb_map (glyph_map) - ; - - auto *out = c->serializer->start_embed (*this); - return_trace (out->serialize (c->serializer, it) && - out->alternates); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (alternates.sanitize (c)); - } - - protected: - Array16Of<HBGlyphID16> - alternates; /* Array of alternate GlyphIDs--in - * arbitrary order */ - public: - DEFINE_SIZE_ARRAY (2, alternates); -}; - -struct AlternateSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - bool may_have_non_1to1 () const - { return false; } - - void closure (hb_closure_context_t *c) const - { - + hb_zip (this+coverage, alternateSet) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) - ; - - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - + hb_zip (this+coverage, alternateSet) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); }) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } - - unsigned - get_glyph_alternates (hb_codepoint_t gid, - unsigned start_offset, - unsigned *alternate_count /* IN/OUT. May be NULL. */, - hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const - { return (this+alternateSet[(this+coverage).get_coverage (gid)]) - .get_alternates (start_offset, alternate_count, alternate_glyphs); } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - - unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - return_trace ((this+alternateSet[index]).apply (c)); - } - - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> alternate_len_list, - hb_array_t<const HBGlyphID16> alternate_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < glyphs.length; i++) - { - unsigned int alternate_len = alternate_len_list[i]; - if (unlikely (!alternateSet[i] - .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len)))) - return_trace (false); - alternate_glyphs_list += alternate_len; - } - return_trace (coverage.serialize_serialize (c, glyphs)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - 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; - - hb_sorted_vector_t<hb_codepoint_t> new_coverage; - + hb_zip (this+coverage, alternateSet) - | hb_filter (glyphset, hb_first) - | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second) - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); - return_trace (bool (new_coverage)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - Array16OfOffset16To<AlternateSet> - alternateSet; /* Array of AlternateSet tables - * ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (6, alternateSet); -}; - -struct AlternateSubst -{ - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> alternate_len_list, - hb_array_t<const HBGlyphID16> alternate_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 1; - u.format = format; - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); - default:return_trace (false); - } - } - - 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, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - AlternateSubstFormat1 format1; - } u; -}; - - -struct Ligature -{ - bool intersects (const hb_set_t *glyphs) const - { return hb_all (component, glyphs); } - - void closure (hb_closure_context_t *c) const - { - if (!intersects (c->glyphs)) return; - c->output->add (ligGlyph); - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - c->input->add_array (component.arrayZ, component.get_length ()); - c->output->add (ligGlyph); - } - - bool would_apply (hb_would_apply_context_t *c) const - { - if (c->len != component.lenP1) - return false; - - for (unsigned int i = 1; i < c->len; i++) - if (likely (c->glyphs[i] != component[i])) - return false; - - return true; - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int count = component.lenP1; - - if (unlikely (!count)) return_trace (false); - - /* Special-case to make it in-place and not consider this - * as a "ligated" substitution. */ - if (unlikely (count == 1)) - { - c->replace_glyph (ligGlyph); - return_trace (true); - } - - unsigned int total_component_count = 0; - - unsigned int match_length = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - - if (likely (!match_input (c, count, - &component[1], - match_glyph, - nullptr, - &match_length, - match_positions, - &total_component_count))) - return_trace (false); - - ligate_input (c, - count, - match_positions, - match_length, - ligGlyph, - total_component_count); - - return_trace (true); - } - - template <typename Iterator, - hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> - bool serialize (hb_serialize_context_t *c, - hb_codepoint_t ligature, - Iterator components /* Starting from second */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - ligGlyph = ligature; - if (unlikely (!component.serialize (c, components))) return_trace (false); - return_trace (true); - } - - bool subset (hb_subset_context_t *c, unsigned coverage_idx) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); - // Ensure Coverage table is always packed after this. - c->serializer->add_virtual_link (coverage_idx); - - auto it = - + hb_iter (component) - | hb_map (glyph_map) - ; - - auto *out = c->serializer->start_embed (*this); - return_trace (out->serialize (c->serializer, - glyph_map[ligGlyph], - it)); - } - - public: - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); - } - - protected: - HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf<HBGlyphID16> - component; /* Array of component GlyphIDs--start - * with the second component--ordered - * in writing direction */ - public: - DEFINE_SIZE_ARRAY (4, component); -}; - -struct LigatureSet -{ - bool intersects (const hb_set_t *glyphs) const - { - return - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) - | hb_any - ; - } - - void closure (hb_closure_context_t *c) const - { - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.closure (c); }) - ; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) - ; - } - - bool would_apply (hb_would_apply_context_t *c) const - { - return - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) - | hb_any - ; - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - { - const Ligature &lig = this+ligature[i]; - if (lig.apply (c)) return_trace (true); - } - - return_trace (false); - } - - bool serialize (hb_serialize_context_t *c, - hb_array_t<const HBGlyphID16> ligatures, - hb_array_t<const unsigned int> component_count_list, - hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); - for (unsigned int i = 0; i < ligatures.length; i++) - { - unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); - if (unlikely (!ligature[i].serialize_serialize (c, - ligatures[i], - component_list.sub_array (0, component_count)))) - return_trace (false); - component_list += component_count; - } - return_trace (true); - } - - bool subset (hb_subset_context_t *c, unsigned coverage_idx) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - + hb_iter (ligature) - | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) - | hb_drain - ; - - if (bool (out->ligature)) - // Ensure Coverage table is always packed after this. - c->serializer->add_virtual_link (coverage_idx); - - return_trace (bool (out->ligature)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (ligature.sanitize (c, this)); - } - - protected: - Array16OfOffset16To<Ligature> - ligature; /* Array LigatureSet tables - * ordered by preference */ - public: - DEFINE_SIZE_ARRAY (2, ligature); -}; - -struct LigatureSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return - + hb_zip (this+coverage, ligatureSet) - | hb_filter (*glyphs, hb_first) - | hb_map (hb_second) - | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_) - { return (this+_).intersects (glyphs); }) - | hb_any - ; - } - - bool may_have_non_1to1 () const - { return true; } - - void closure (hb_closure_context_t *c) const - { - + hb_zip (this+coverage, ligatureSet) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) - ; - - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - - + hb_zip (this+coverage, ligatureSet) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { - unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); - if (likely (index == NOT_COVERED)) return false; - - const LigatureSet &lig_set = this+ligatureSet[index]; - return lig_set.would_apply (c); - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - const LigatureSet &lig_set = this+ligatureSet[index]; - return_trace (lig_set.apply (c)); - } - - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> first_glyphs, - hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, - hb_array_t<const HBGlyphID16> ligatures_list, - hb_array_t<const unsigned int> component_count_list, - hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < first_glyphs.length; i++) - { - unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; - if (unlikely (!ligatureSet[i] - .serialize_serialize (c, - ligatures_list.sub_array (0, ligature_count), - component_count_list.sub_array (0, ligature_count), - component_list))) return_trace (false); - ligatures_list += ligature_count; - component_count_list += ligature_count; - } - return_trace (coverage.serialize_serialize (c, first_glyphs)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - 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; - - // Due to a bug in some older versions of windows 7 the Coverage table must be - // packed after the LigatureSet and Ligature tables, so serialize Coverage first - // which places it last in the packed order. - hb_set_t new_coverage; - + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) - | hb_filter (glyphset, hb_first) - | hb_filter ([&] (const LigatureSet& _) { - return _.intersects (&glyphset); - }, hb_second) - | hb_map (hb_first) - | hb_sink (new_coverage); - - if (!c->serializer->push<Coverage> () - ->serialize (c->serializer, - + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) - { - c->serializer->pop_discard (); - return_trace (false); - } - - unsigned coverage_idx = c->serializer->pop_pack (); - c->serializer->add_link (out->coverage, coverage_idx); - - + hb_zip (this+coverage, ligatureSet) - | hb_filter (new_coverage, hb_first) - | hb_map (hb_second) - // to ensure that the repacker always orders the coverage table after the LigatureSet - // and LigatureSubtable's they will be linked to the Coverage table via a virtual link - // the coverage table object idx is passed down to facilitate this. - | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) - ; - - return_trace (bool (new_coverage)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - Array16OfOffset16To<LigatureSet> - ligatureSet; /* Array LigatureSet tables - * ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (6, ligatureSet); -}; - -struct LigatureSubst -{ - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> first_glyphs, - hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, - hb_array_t<const HBGlyphID16> ligatures_list, - hb_array_t<const unsigned int> component_count_list, - hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 1; - u.format = format; - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, - first_glyphs, - ligature_per_first_glyph_count_list, - ligatures_list, - component_count_list, - component_list)); - default:return_trace (false); - } - } - - 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, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - LigatureSubstFormat1 format1; - } u; -}; - - -struct ContextSubst : Context {}; - -struct ChainContextSubst : ChainContext {}; - -struct ExtensionSubst : Extension<ExtensionSubst> -{ - typedef struct SubstLookupSubTable SubTable; - bool is_reverse () const; -}; - - -struct ReverseChainSingleSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - if (!(this+coverage).intersects (glyphs)) - return false; - - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - - unsigned int count; - - count = backtrack.len; - for (unsigned int i = 0; i < count; i++) - if (!(this+backtrack[i]).intersects (glyphs)) - return false; - - count = lookahead.len; - for (unsigned int i = 0; i < count; i++) - if (!(this+lookahead[i]).intersects (glyphs)) - return false; - - return true; - } - - bool may_have_non_1to1 () const - { return false; } - - void closure (hb_closure_context_t *c) const - { - if (!intersects (c->glyphs)) return; - - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); - - + hb_zip (this+coverage, substitute) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_sink (c->output) - ; - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - - unsigned int count; - - count = backtrack.len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; - - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - count = lookahead.len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; - - const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); - count = substitute.len; - c->output->add_array (substitute.arrayZ, substitute.len); - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) - return_trace (false); /* No chaining to this type */ - - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); - - if (unlikely (index >= substitute.len)) return_trace (false); - - unsigned int start_index = 0, end_index = 0; - if (match_backtrack (c, - backtrack.len, (HBUINT16 *) backtrack.arrayZ, - match_coverage, this, - &start_index) && - match_lookahead (c, - lookahead.len, (HBUINT16 *) lookahead.arrayZ, - match_coverage, this, - 1, &end_index)) - { - c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); - c->replace_glyph_inplace (substitute[index]); - /* Note: We DON'T decrease buffer->idx. The main loop does it - * for us. This is useful for preventing surprises if someone - * calls us through a Context lookup. */ - return_trace (true); - } - - return_trace (false); - } - - template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const - { - TRACE_SERIALIZE (this); - auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> (); - - if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) - return_trace (false); - - for (auto& offset : it) { - auto *o = out->serialize_append (c->serializer); - if (unlikely (!o) || !o->serialize_subset (c, offset, this)) - return_trace (false); - } - - return_trace (true); - } - - template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator, - hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)), - hb_requires (hb_is_iterator (BacktrackIterator)), - hb_requires (hb_is_iterator (LookaheadIterator))> - bool serialize (hb_subset_context_t *c, - Iterator coverage_subst_iter, - BacktrackIterator backtrack_iter, - LookaheadIterator lookahead_iter) const - { - TRACE_SERIALIZE (this); - - auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->check_success (out))) return_trace (false); - if (unlikely (!c->serializer->embed (this->format))) return_trace (false); - if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); - - if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false); - if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false); - - auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> (); - auto substitutes = - + coverage_subst_iter - | hb_map (hb_second) - ; - - auto glyphs = - + coverage_subst_iter - | hb_map_retains_sorting (hb_first) - ; - if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes)))) - return_trace (false); - - if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs))) - return_trace (false); - return_trace (true); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); - - auto it = - + hb_zip (this+coverage, substitute) - | hb_filter (glyphset, hb_first) - | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t - { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) - ; - - return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ())); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) - return_trace (false); - const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); - if (!lookahead.sanitize (c, this)) - return_trace (false); - const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead); - return_trace (substitute.sanitize (c)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of table */ - Array16OfOffset16To<Coverage> - backtrack; /* Array of coverage tables - * in backtracking sequence, in glyph - * sequence order */ - Array16OfOffset16To<Coverage> - lookaheadX; /* Array of coverage tables - * in lookahead sequence, in glyph - * sequence order */ - Array16Of<HBGlyphID16> - substituteX; /* Array of substitute - * GlyphIDs--ordered by Coverage Index */ - public: - DEFINE_SIZE_MIN (10); -}; - -struct ReverseChainSingleSubst -{ - 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, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - ReverseChainSingleSubstFormat1 format1; - } u; -}; - - - -/* - * SubstLookup - */ - -struct SubstLookupSubTable -{ - friend struct Lookup; - friend struct SubstLookup; - - enum Type { - Single = 1, - Multiple = 2, - Alternate = 3, - Ligature = 4, - Context = 5, - ChainContext = 6, - Extension = 7, - ReverseChainSingle = 8 - }; - - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const - { - TRACE_DISPATCH (this, lookup_type); - switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...)); - case Multiple: return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...)); - case Alternate: return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...)); - case Ligature: return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...)); - case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...)); - case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...)); - case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...)); - case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...)); - default: return_trace (c->default_return_value ()); - } - } - - bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const - { - hb_intersects_context_t c (glyphs); - return dispatch (&c, lookup_type); - } - - protected: - union { - SingleSubst single; - MultipleSubst multiple; - AlternateSubst alternate; - LigatureSubst ligature; - ContextSubst context; - ChainContextSubst chainContext; - ExtensionSubst extension; - ReverseChainSingleSubst reverseChainContextSingle; - } u; - public: - DEFINE_SIZE_MIN (0); -}; - - -struct SubstLookup : Lookup -{ - typedef SubstLookupSubTable SubTable; - - const SubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<SubTable> (i); } - - static inline bool lookup_type_is_reverse (unsigned int lookup_type) - { return lookup_type == SubTable::ReverseChainSingle; } - - bool is_reverse () const - { - unsigned int type = get_type (); - if (unlikely (type == SubTable::Extension)) - return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse (); - return lookup_type_is_reverse (type); - } - - bool may_have_non_1to1 () const - { - hb_have_non_1to1_context_t c; - return dispatch (&c); - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - return_trace (dispatch (c)); - } - - bool intersects (const hb_set_t *glyphs) const - { - hb_intersects_context_t c (glyphs); - return dispatch (&c); - } - - hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const - { - if (!c->should_visit_lookup (this_index)) - return hb_closure_context_t::default_return_value (); - - c->set_recurse_func (dispatch_closure_recurse_func); - - hb_closure_context_t::return_t ret = dispatch (c); - - c->flush (); - - return ret; - } - - hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const - { - if (c->is_lookup_visited (this_index)) - return hb_closure_lookups_context_t::default_return_value (); - - c->set_lookup_visited (this_index); - if (!intersects (c->glyphs)) - { - c->set_lookup_inactive (this_index); - return hb_closure_lookups_context_t::default_return_value (); - } - - c->set_recurse_func (dispatch_closure_lookups_recurse_func); - - hb_closure_lookups_context_t::return_t ret = dispatch (c); - return ret; - } - - hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const - { - c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); - return dispatch (c); - } - - template <typename set_t> - void collect_coverage (set_t *glyphs) const - { - hb_collect_coverage_context_t<set_t> c (glyphs); - dispatch (&c); - } - - bool would_apply (hb_would_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t *accel) const - { - if (unlikely (!c->len)) return false; - if (!accel->may_have (c->glyphs[0])) return false; - return dispatch (c); - } - - static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); - - bool serialize_single (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const HBGlyphID16> substitutes) - { - TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); - if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes))) - { - c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); - return_trace (true); - } - c->pop_discard (); - return_trace (false); - } - - bool serialize_multiple (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); - if (c->push<SubTable> ()->u.multiple. - serialize (c, - glyphs, - substitute_len_list, - substitute_glyphs_list)) - { - c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); - return_trace (true); - } - c->pop_discard (); - return_trace (false); - } - - bool serialize_alternate (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> alternate_len_list, - hb_array_t<const HBGlyphID16> alternate_glyphs_list) - { - TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); - - if (c->push<SubTable> ()->u.alternate. - serialize (c, - glyphs, - alternate_len_list, - alternate_glyphs_list)) - { - c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); - return_trace (true); - } - c->pop_discard (); - return_trace (false); - } - - bool serialize_ligature (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t<const HBGlyphID16> first_glyphs, - hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, - hb_array_t<const HBGlyphID16> ligatures_list, - hb_array_t<const unsigned int> component_count_list, - hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); - if (c->push<SubTable> ()->u.ligature. - serialize (c, - first_glyphs, - ligature_per_first_glyph_count_list, - ligatures_list, - component_count_list, - component_list)) - { - c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); - return_trace (true); - } - c->pop_discard (); - return_trace (false); - } - - template <typename context_t> - static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - - static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index); - - static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) - { - if (!c->should_visit_lookup (lookup_index)) - return hb_empty_t (); - - hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); - - /* While in theory we should flush here, it will cause timeouts because a recursive - * lookup can keep growing the glyph set. Skip, and outer loop will retry up to - * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */ - //c->flush (); - - return ret; - } - - HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index); - - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } - - bool subset (hb_subset_context_t *c) const - { return Lookup::subset<SubTable> (c); } - - bool sanitize (hb_sanitize_context_t *c) const - { return Lookup::sanitize<SubTable> (c); } -}; - -/* - * GSUB -- Glyph Substitution - * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub - */ - -struct GSUB : GSUBGPOS -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB; - - const SubstLookup& get_lookup (unsigned int i) const - { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); } - - bool subset (hb_subset_context_t *c) const - { - hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features); - return GSUBGPOS::subset<SubstLookup> (&l); - } - - bool sanitize (hb_sanitize_context_t *c) const - { return GSUBGPOS::sanitize<SubstLookup> (c); } - - HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, - hb_face_t *face) const; - - void closure_lookups (hb_face_t *face, - const hb_set_t *glyphs, - hb_set_t *lookup_indexes /* IN/OUT */) const - { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); } - - typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t; -}; - - -struct GSUB_accelerator_t : GSUB::accelerator_t {}; - +using Layout::GSUB::SubstLookup; +using Layout::GSUB::ExtensionSubst; +// TODO(garretrieger): Move into the new layout directory. /* Out-of-class implementation for methods recursing */ #ifndef HB_NO_OT_LAYOUT diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh index 191d3bebc5..c9750ff63b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -125,24 +125,31 @@ struct hb_closure_context_t : hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index); if (unlikely (covered_glyph_set->in_error ())) return true; - if (parent_active_glyphs ()->is_subset (*covered_glyph_set)) + if (parent_active_glyphs ().is_subset (*covered_glyph_set)) return true; - hb_set_union (covered_glyph_set, parent_active_glyphs ()); + covered_glyph_set->union_ (parent_active_glyphs ()); return false; } - hb_set_t* parent_active_glyphs () + const hb_set_t& previous_parent_active_glyphs () { + if (active_glyphs_stack.length <= 1) + return *glyphs; + + return active_glyphs_stack[active_glyphs_stack.length - 2]; + } + + const hb_set_t& parent_active_glyphs () { - if (active_glyphs_stack.length < 1) - return glyphs; + if (!active_glyphs_stack) + return *glyphs; return active_glyphs_stack.tail (); } - void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set) + hb_set_t& push_cur_active_glyphs () { - active_glyphs_stack.push (cur_active_glyph_set); + return *active_glyphs_stack.push (); } bool pop_cur_done_glyphs () @@ -156,29 +163,24 @@ struct hb_closure_context_t : hb_face_t *face; hb_set_t *glyphs; - hb_set_t *cur_intersected_glyphs; hb_set_t output[1]; - hb_vector_t<hb_set_t *> active_glyphs_stack; + hb_vector_t<hb_set_t> active_glyphs_stack; recurse_func_t recurse_func; unsigned int nesting_level_left; hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, - hb_set_t *cur_intersected_glyphs_, hb_map_t *done_lookups_glyph_count_, hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_, unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), glyphs (glyphs_), - cur_intersected_glyphs (cur_intersected_glyphs_), recurse_func (nullptr), nesting_level_left (nesting_level_left_), done_lookups_glyph_count (done_lookups_glyph_count_), done_lookups_glyph_set (done_lookups_glyph_set_), lookup_count (0) - { - push_cur_active_glyphs (glyphs_); - } + {} ~hb_closure_context_t () { flush (); } @@ -186,11 +188,11 @@ struct hb_closure_context_t : void flush () { - hb_set_del_range (output, face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */ - hb_set_union (glyphs, output); - hb_set_clear (output); + output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */ + glyphs->union_ (*output); + output->clear (); active_glyphs_stack.pop (); - active_glyphs_stack.fini (); + active_glyphs_stack.reset (); } private: @@ -406,12 +408,11 @@ struct hb_ot_apply_context_t : { matcher_t () : lookup_props (0), + mask (-1), ignore_zwnj (false), ignore_zwj (false), - mask (-1), -#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ - syllable arg1(0), -#undef arg1 + per_syllable (false), + syllable {0}, match_func (nullptr), match_data (nullptr) {} @@ -421,7 +422,8 @@ struct hb_ot_apply_context_t : void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } void set_mask (hb_mask_t mask_) { mask = mask_; } - void set_syllable (uint8_t syllable_) { syllable = syllable_; } + void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; } + void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; } void set_match_func (match_func_t match_func_, const void *match_data_) { match_func = match_func_; match_data = match_data_; } @@ -467,9 +469,10 @@ struct hb_ot_apply_context_t : protected: unsigned int lookup_props; + hb_mask_t mask; bool ignore_zwnj; bool ignore_zwj; - hb_mask_t mask; + bool per_syllable; uint8_t syllable; match_func_t match_func; const void *match_data; @@ -488,6 +491,7 @@ struct hb_ot_apply_context_t : /* Ignore ZWJ if we are matching context, or asked to. */ matcher.set_ignore_zwj (context_match || c->auto_zwj); matcher.set_mask (context_match ? -1 : c->lookup_mask); + matcher.set_per_syllable (c->per_syllable); } void set_lookup_props (unsigned int lookup_props) { @@ -520,7 +524,7 @@ struct hb_ot_apply_context_t : may_skip (const hb_glyph_info_t &info) const { return matcher.may_skip (c, info); } - bool next () + bool next (unsigned *unsafe_to = nullptr) { assert (num_items > 0); while (idx + num_items < end) @@ -543,11 +547,17 @@ struct hb_ot_apply_context_t : } if (skip == matcher_t::SKIP_NO) + { + if (unsafe_to) + *unsafe_to = idx + 1; return false; + } } + if (unsafe_to) + *unsafe_to = end; return false; } - bool prev () + bool prev (unsigned *unsafe_from = nullptr) { assert (num_items > 0); while (idx > num_items - 1) @@ -570,8 +580,14 @@ struct hb_ot_apply_context_t : } if (skip == matcher_t::SKIP_NO) + { + if (unsafe_from) + *unsafe_from = hb_max (1u, idx) - 1u; return false; + } } + if (unsafe_from) + *unsafe_from = 0; return false; } @@ -622,6 +638,7 @@ struct hb_ot_apply_context_t : bool has_glyph_classes; bool auto_zwnj; bool auto_zwj; + bool per_syllable; bool random; uint32_t random_state; @@ -650,6 +667,7 @@ struct hb_ot_apply_context_t : has_glyph_classes (gdef.has_glyph_classes ()), auto_zwnj (true), auto_zwj (true), + per_syllable (false), random (false), random_state (1) { init_iters (); } @@ -662,6 +680,7 @@ struct hb_ot_apply_context_t : void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); } void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } + void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); } void set_random (bool random_) { random = random_; } void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } @@ -712,53 +731,60 @@ struct hb_ot_apply_context_t : return true; } - void _set_glyph_props (hb_codepoint_t glyph_index, + 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 &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; + _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index)); + } else if (class_guess) - _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); + { + props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; + _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess); + } + else + _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); (void) 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 { - _set_glyph_props (glyph_index, class_guess, true); + _set_glyph_class (glyph_index, class_guess, true); (void) buffer->replace_glyph (glyph_index); } void output_glyph_for_component (hb_codepoint_t glyph_index, unsigned int class_guess) const { - _set_glyph_props (glyph_index, class_guess, false, true); + _set_glyph_class (glyph_index, class_guess, false, true); (void) buffer->output_glyph (glyph_index); } }; @@ -948,7 +974,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, const HBUINT16 input[], /* Array of input values--start with second glyph */ match_func_t match_func, const void *match_data, - unsigned int *end_offset, + unsigned int *end_position, unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], unsigned int *p_total_component_count = nullptr) { @@ -1001,7 +1027,12 @@ static inline bool match_input (hb_ot_apply_context_t *c, match_positions[0] = buffer->idx; for (unsigned int i = 1; i < count; i++) { - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + *end_position = unsafe_to; + return_trace (false); + } match_positions[i] = skippy_iter.idx; @@ -1055,7 +1086,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); } - *end_offset = skippy_iter.idx - buffer->idx + 1; + *end_position = skippy_iter.idx + 1; if (p_total_component_count) *p_total_component_count = total_component_count; @@ -1065,7 +1096,7 @@ static inline bool match_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 */ const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ - unsigned int match_length, + unsigned int match_end, hb_codepoint_t lig_glyph, unsigned int total_component_count) { @@ -1073,7 +1104,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, hb_buffer_t *buffer = c->buffer; - buffer->merge_clusters (buffer->idx, buffer->idx + match_length); + buffer->merge_clusters (buffer->idx, match_end); /* - If a base and one or more marks ligate, consider that as a base, NOT * ligature, such that all following marks can still attach to it. @@ -1190,11 +1221,16 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c, skippy_iter.set_match_func (match_func, match_data, backtrack); for (unsigned int i = 0; i < count; i++) - if (!skippy_iter.prev ()) + { + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + *match_start = unsafe_from; return_trace (false); + } + } *match_start = skippy_iter.idx; - return_trace (true); } @@ -1203,21 +1239,26 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c, const HBUINT16 lookahead[], match_func_t match_func, const void *match_data, - unsigned int offset, + unsigned int start_index, unsigned int *end_index) { TRACE_APPLY (nullptr); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; - skippy_iter.reset (c->buffer->idx + offset - 1, count); + skippy_iter.reset (start_index - 1, count); skippy_iter.set_match_func (match_func, match_data, lookahead); for (unsigned int i = 0; i < count; i++) - if (!skippy_iter.next ()) + { + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + *end_index = unsafe_to; return_trace (false); + } + } *end_index = skippy_iter.idx + 1; - return_trace (true); } @@ -1284,22 +1325,23 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, unsigned seqIndex = lookupRecord[i].sequenceIndex; if (seqIndex >= inputCount) continue; - hb_set_t *pos_glyphs = nullptr; + bool has_pos_glyphs = false; + hb_set_t pos_glyphs; - if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex)) + if (!hb_set_has (covered_seq_indicies, seqIndex)) { - pos_glyphs = hb_set_create (); + has_pos_glyphs = true; if (seqIndex == 0) { switch (context_format) { case ContextFormat::SimpleContext: - pos_glyphs->add (value); + pos_glyphs.add (value); break; case ContextFormat::ClassBasedContext: - intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs); + intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs); break; case ContextFormat::CoverageBasedContext: - hb_set_set (pos_glyphs, c->cur_intersected_glyphs); + pos_glyphs.set (c->parent_active_glyphs ()); break; } } @@ -1313,12 +1355,16 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, input_value = input[seqIndex - 1]; } - intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs); + intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs); } } - hb_set_add (covered_seq_indicies, seqIndex); - c->push_cur_active_glyphs (pos_glyphs ? pos_glyphs : c->glyphs); + covered_seq_indicies->add (seqIndex); + if (has_pos_glyphs) { + c->push_cur_active_glyphs () = std::move (pos_glyphs); + } else { + c->push_cur_active_glyphs ().set (*c->glyphs); + } unsigned endIndex = inputCount; if (context_format == ContextFormat::CoverageBasedContext) @@ -1327,8 +1373,6 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex); c->pop_cur_done_glyphs (); - if (pos_glyphs) - hb_set_destroy (pos_glyphs); } hb_set_destroy (covered_seq_indicies); @@ -1343,15 +1387,13 @@ static inline void recurse_lookups (context_t *c, c->recurse (lookupRecord[i].lookupListIndex); } -static inline bool 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 match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ - unsigned int match_length) + unsigned int match_end) { - TRACE_APPLY (nullptr); - hb_buffer_t *buffer = c->buffer; int end; @@ -1359,7 +1401,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, * Adjust. */ { unsigned int bl = buffer->backtrack_len (); - end = bl + match_length; + end = bl + match_end - buffer->idx; int delta = bl - buffer->idx; /* Convert positions to new indexing. */ @@ -1373,9 +1415,10 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, if (idx >= count) continue; - /* Don't recurse to ourself at same position. - * Note that this test is too naive, it doesn't catch longer loops. */ - if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)) + unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); + + /* This can happen if earlier recursed lookups deleted many entries. */ + if (unlikely (match_positions[idx] >= orig_len)) continue; if (unlikely (!buffer->move_to (match_positions[idx]))) @@ -1384,7 +1427,6 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, if (unlikely (buffer->max_ops <= 0)) break; - unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); if (!c->recurse (lookupRecord[i].lookupListIndex)) continue; @@ -1410,25 +1452,27 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, * NOT the one after it. * * - If buffer length was decreased by n, it does not necessarily - * mean that n match positions where removed, as there might - * have been marks and default-ignorables in the sequence. We - * should instead drop match positions between current-position - * and current-position + n instead. Though, am not sure which - * one is better. Both cases have valid uses. Sigh. + * mean that n match positions where removed, as there recursed-to + * lookup might had a different LookupFlag. Here's a constructed + * case of that: + * https://github.com/harfbuzz/harfbuzz/discussions/3538 * * It should be possible to construct tests for both of these cases. */ end += delta; - if (end <= int (match_positions[idx])) + if (end < int (match_positions[idx])) { /* End might end up being smaller than match_positions[idx] if the recursed - * lookup ended up removing many items, more than we have had matched. - * Just never rewind end back and get out of here. - * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */ + * lookup ended up removing many items. + * Just never rewind end beyond start of current position, since that is + * not possible in the recursed lookup. Also adjust delta as such. + * + * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 + * https://github.com/harfbuzz/harfbuzz/issues/1611 + */ + delta += match_positions[idx] - end; end = match_positions[idx]; - /* There can't be any further changes. */ - break; } unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ @@ -1440,7 +1484,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, } else { - /* NOTE: delta is negative. */ + /* NOTE: delta is non-positive. */ delta = hb_max (delta, (int) next - (int) count); next -= delta; } @@ -1461,8 +1505,6 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, } (void) buffer->move_to (end); - - return_trace (true); } @@ -1550,17 +1592,25 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, const LookupRecord lookupRecord[], ContextApplyLookupContext &lookup_context) { - unsigned int match_length = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - return match_input (c, - inputCount, input, - lookup_context.funcs.match, lookup_context.match_data, - &match_length, match_positions) - && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length), - apply_lookup (c, - inputCount, match_positions, - lookupCount, lookupRecord, - match_length)); + unsigned match_end = 0; + unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; + if (match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data, + &match_end, match_positions)) + { + c->buffer->unsafe_to_break (c->buffer->idx, match_end); + apply_lookup (c, + inputCount, match_positions, + lookupCount, lookupRecord, + match_end); + return true; + } + else + { + c->buffer->unsafe_to_concat (c->buffer->idx, match_end); + return false; + } } struct Rule @@ -1828,8 +1878,9 @@ struct ContextFormat1 void closure (hb_closure_context_t *c) const { - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); struct ContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -1838,10 +1889,14 @@ struct ContextFormat1 }; + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) - | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_filter ([&] (hb_codepoint_t _) { + return c->previous_parent_active_glyphs ().has (_); + }, hb_first) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); }) | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -1989,8 +2044,9 @@ struct ContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); const ClassDef &class_def = this+classDef; @@ -2000,10 +2056,9 @@ struct ContextFormat2 &class_def }; - return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return class_def.intersects_class (c->cur_intersected_glyphs, _); }, + { return class_def.intersects_class (&c->parent_active_glyphs (), _); }, hb_first) | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _) { @@ -2011,6 +2066,8 @@ struct ContextFormat2 rule_set.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2183,8 +2240,10 @@ struct ContextFormat3 if (!(this+coverageZ[0]).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextClosureLookupContext lookup_context = { @@ -2196,6 +2255,8 @@ struct ContextFormat3 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, 0, lookup_context); + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2452,25 +2513,38 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, const LookupRecord lookupRecord[], ChainContextApplyLookupContext &lookup_context) { - unsigned int start_index = 0, match_length = 0, end_index = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - return match_input (c, - inputCount, input, - lookup_context.funcs.match, lookup_context.match_data[1], - &match_length, match_positions) - && match_backtrack (c, - backtrackCount, backtrack, - lookup_context.funcs.match, lookup_context.match_data[0], - &start_index) - && match_lookahead (c, - lookaheadCount, lookahead, - lookup_context.funcs.match, lookup_context.match_data[2], - match_length, &end_index) - && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index), - apply_lookup (c, - inputCount, match_positions, - lookupCount, lookupRecord, - match_length)); + unsigned end_index = c->buffer->idx; + unsigned match_end = 0; + unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; + if (!(match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data[1], + &match_end, match_positions) && (end_index = match_end) + && match_lookahead (c, + lookaheadCount, lookahead, + lookup_context.funcs.match, lookup_context.match_data[2], + match_end, &end_index))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, end_index); + return false; + } + + unsigned start_index = c->buffer->out_len; + if (!match_backtrack (c, + backtrackCount, backtrack, + lookup_context.funcs.match, lookup_context.match_data[0], + &start_index)) + { + c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); + return false; + } + + c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); + apply_lookup (c, + inputCount, match_positions, + lookupCount, lookupRecord, + match_end); + return true; } struct ChainRule @@ -2802,8 +2876,9 @@ struct ChainContextFormat1 void closure (hb_closure_context_t *c) const { - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -2812,10 +2887,14 @@ struct ChainContextFormat1 }; + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) - | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_filter ([&] (hb_codepoint_t _) { + return c->previous_parent_active_glyphs ().has (_); + }, hb_first) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); }) | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2964,8 +3043,10 @@ struct ChainContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; @@ -2979,10 +3060,9 @@ struct ChainContextFormat2 &lookahead_class_def} }; - return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); }, + { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); }, hb_first) | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _) { @@ -2990,6 +3070,8 @@ struct ChainContextFormat2 chainrule_set.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -3216,8 +3298,10 @@ struct ChainContextFormat3 if (!(this+input[0]).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input); const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead); @@ -3232,6 +3316,8 @@ struct ChainContextFormat3 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, lookup.len, lookup.arrayZ, 0, lookup_context); + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -3706,7 +3792,7 @@ struct GSUBGPOS for (unsigned i : feature_indices->iter ()) { hb_tag_t t = get_feature_tag (i); - if (t == unique_features.INVALID_KEY) continue; + if (t == HB_MAP_VALUE_INVALID) continue; if (!unique_features.has (t)) { hb_set_t* indices = hb_set_create (); @@ -3839,7 +3925,7 @@ struct GSUBGPOS template <typename T> struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<T> (face); if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) @@ -3861,8 +3947,7 @@ struct GSUBGPOS for (unsigned int i = 0; i < this->lookup_count; i++) this->accels[i].init (table->get_lookup (i)); } - - void fini () + ~accelerator_t () { for (unsigned int i = 0; i < this->lookup_count; i++) this->accels[i].fini (); diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc index 60733648c1..f4ea21a4f9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.cc +++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc @@ -54,6 +54,8 @@ #include "hb-aat-layout-morx-table.hh" #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise. +using OT::Layout::GSUB::GSUB; + /** * SECTION:hb-ot-layout * @title: hb-ot-layout @@ -361,6 +363,13 @@ hb_ot_layout_get_attach_points (hb_face_t *face, * Fetches a list of the caret positions defined for a ligature glyph in the GDEF * table of the font. The list returned will begin at the offset provided. * + * Note that a ligature that is formed from n characters will have n-1 + * caret positions. The first character is not represented in the array, + * since its caret position is the glyph position. + * + * The positions returned by this function are 'unshaped', and will have to + * be fixed up for kerning that may be applied to the ligature glyph. + * * Return value: Total number of ligature caret positions for @glyph. * **/ @@ -382,7 +391,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font, */ bool -OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED, +GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED, hb_face_t *face) const { #ifdef HB_NO_OT_LAYOUT_BLOCKLIST @@ -999,7 +1008,7 @@ struct hb_collect_features_context_t hb_collect_features_context_t (hb_face_t *face, hb_tag_t table_tag, hb_set_t *feature_indices_, - const hb_tag_t *features) + const hb_tag_t *features) : g (get_gsubgpos_table (face, table_tag)), feature_indices (feature_indices_), @@ -1026,7 +1035,7 @@ struct hb_collect_features_context_t { hb_tag_t tag = g.get_feature_tag (i); if (features_set.has (tag)) - feature_indices_filter.add(i); + feature_indices_filter.add(i); } } @@ -1491,10 +1500,9 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs /* OUT */) { - hb_set_t cur_intersected_glyphs; hb_map_t done_lookups_glyph_count; hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; - OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); + OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); @@ -1520,11 +1528,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, const hb_set_t *lookups, hb_set_t *glyphs /* OUT */) { - hb_set_t cur_intersected_glyphs; hb_map_t done_lookups_glyph_count; hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; - OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); - const OT::GSUB& gsub = *face->table.GSUB->table; + OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); + const GSUB& gsub = *face->table.GSUB->table; unsigned int iteration_count = 0; unsigned int glyphs_length; @@ -1803,7 +1810,7 @@ struct GSUBProxy table (*face->table.GSUB->table), accels (face->table.GSUB->accels) {} - const OT::GSUB &table; + const GSUB &table; const OT::hb_ot_layout_lookup_accelerator_t *accels; }; @@ -1890,7 +1897,7 @@ apply_string (OT::hb_ot_apply_context_t *c, apply_forward (c, accel); if (!Proxy::inplace) - buffer->swap_buffers (); + buffer->sync (); } else { @@ -1924,6 +1931,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, c.set_auto_zwj (lookups[table_index][i].auto_zwj); c.set_auto_zwnj (lookups[table_index][i].auto_zwnj); c.set_random (lookups[table_index][i].random); + c.set_per_syllable (lookups[table_index][i].per_syllable); apply_string<Proxy> (&c, proxy.table.get_lookup (lookup_index), @@ -1962,13 +1970,84 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, #ifndef HB_NO_BASE /** + * hb_ot_layout_get_horizontal_baseline_tag_for_script: + * @script: a script tag. + * + * Fetches the dominant horizontal baseline tag used by @script. + * + * Return value: dominant baseline tag for the @script. + * + * Since: 4.0.0 + **/ +hb_ot_layout_baseline_tag_t +hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script) +{ + /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */ + switch ((int) script) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_BENGALI: + case HB_SCRIPT_DEVANAGARI: + case HB_SCRIPT_GUJARATI: + case HB_SCRIPT_GURMUKHI: + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: + /* Unicode-4.0 additions */ + case HB_SCRIPT_LIMBU: + /* Unicode-4.1 additions */ + case HB_SCRIPT_SYLOTI_NAGRI: + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHAGS_PA: + /* Unicode-5.2 additions */ + case HB_SCRIPT_MEETEI_MAYEK: + /* Unicode-6.1 additions */ + case HB_SCRIPT_SHARADA: + case HB_SCRIPT_TAKRI: + /* Unicode-7.0 additions */ + case HB_SCRIPT_MODI: + case HB_SCRIPT_SIDDHAM: + case HB_SCRIPT_TIRHUTA: + /* Unicode-9.0 additions */ + case HB_SCRIPT_MARCHEN: + case HB_SCRIPT_NEWA: + /* Unicode-10.0 additions */ + case HB_SCRIPT_SOYOMBO: + case HB_SCRIPT_ZANABAZAR_SQUARE: + /* Unicode-11.0 additions */ + case HB_SCRIPT_DOGRA: + case HB_SCRIPT_GUNJALA_GONDI: + /* Unicode-12.0 additions */ + case HB_SCRIPT_NANDINAGARI: + return HB_OT_LAYOUT_BASELINE_TAG_HANGING; + + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + case HB_SCRIPT_HAN: + case HB_SCRIPT_HIRAGANA: + case HB_SCRIPT_KATAKANA: + /* Unicode-3.0 additions */ + case HB_SCRIPT_BOPOMOFO: + /* Unicode-9.0 additions */ + case HB_SCRIPT_TANGUT: + /* Unicode-10.0 additions */ + case HB_SCRIPT_NUSHU: + /* Unicode-13.0 additions */ + case HB_SCRIPT_KHITAN_SMALL_SCRIPT: + return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT; + + default: + return HB_OT_LAYOUT_BASELINE_TAG_ROMAN; + } +} + +/** * hb_ot_layout_get_baseline: * @font: a font * @baseline_tag: a baseline tag * @direction: text direction. * @script_tag: script tag. * @language_tag: language tag, currently unused. - * @coord: (out): baseline value if found. + * @coord: (out) (nullable): baseline value if found. * * Fetches a baseline value from the face. * @@ -1984,13 +2063,231 @@ hb_ot_layout_get_baseline (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT. May be NULL. */) { - bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord); + return font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord); +} + +/** + * hb_ot_layout_get_baseline_with_fallback: + * @font: a font + * @baseline_tag: a baseline tag + * @direction: text direction. + * @script_tag: script tag. + * @language_tag: language tag, currently unused. + * @coord: (out): baseline value if found. + * + * Fetches a baseline value from the face, and synthesizes + * it if the font does not have it. + * + * Since: 4.0.0 + **/ +void +hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT */) +{ + if (hb_ot_layout_get_baseline (font, + baseline_tag, + direction, + script_tag, + language_tag, + coord)) + return; + + /* Synthesize missing baselines. + * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts + */ + switch (baseline_tag) + { + case HB_OT_LAYOUT_BASELINE_TAG_ROMAN: + *coord = 0; // FIXME origin ? + break; + + case HB_OT_LAYOUT_BASELINE_TAG_MATH: + { + hb_codepoint_t glyph; + hb_glyph_extents_t extents; + if (HB_DIRECTION_IS_HORIZONTAL (direction) && + (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) || + hb_font_get_nominal_glyph (font, '-', &glyph)) && + hb_font_get_glyph_extents (font, glyph, &extents)) + { + *coord = extents.y_bearing + extents.height / 2; + } + else + { + hb_position_t x_height = font->y_scale / 2; +#ifndef HB_NO_METRICS + hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height); +#endif + *coord = x_height / 2; + } + } + break; - if (result && coord) - *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord); + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: + { + hb_position_t embox_top, embox_bottom; + + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &embox_top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &embox_bottom); + + if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT) + *coord = embox_top + (embox_bottom - embox_top) / 10; + else + *coord = embox_bottom + (embox_top - embox_bottom) / 10; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: + if (hb_ot_layout_get_baseline (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + coord)) + *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + else + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, direction, &font_extents); + *coord = font_extents.ascender; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: + if (hb_ot_layout_get_baseline (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + coord)) + *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + else + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, direction, &font_extents); + *coord = font_extents.descender; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_HANGING: + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + { + hb_codepoint_t ch; + hb_codepoint_t glyph; + hb_glyph_extents_t extents; - return result; + /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */ + switch ((int) script_tag) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_BENGALI: ch = 0x0995u; break; + case HB_SCRIPT_DEVANAGARI: ch = 0x0915u; break; + case HB_SCRIPT_GUJARATI: ch = 0x0a95u; break; + case HB_SCRIPT_GURMUKHI: ch = 0x0a15u; break; + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: ch = 0x0f40u; break; + /* Unicode-4.0 additions */ + case HB_SCRIPT_LIMBU: ch = 0x1901u; break; + /* Unicode-4.1 additions */ + case HB_SCRIPT_SYLOTI_NAGRI: ch = 0xa807u; break; + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHAGS_PA: ch = 0xa840u; break; + /* Unicode-5.2 additions */ + case HB_SCRIPT_MEETEI_MAYEK: ch = 0xabc0u; break; + /* Unicode-6.1 additions */ + case HB_SCRIPT_SHARADA: ch = 0x11191u; break; + case HB_SCRIPT_TAKRI: ch = 0x1168cu; break; + /* Unicode-7.0 additions */ + case HB_SCRIPT_MODI: ch = 0x1160eu;break; + case HB_SCRIPT_SIDDHAM: ch = 0x11590u; break; + case HB_SCRIPT_TIRHUTA: ch = 0x1148fu; break; + /* Unicode-9.0 additions */ + case HB_SCRIPT_MARCHEN: ch = 0x11c72u; break; + case HB_SCRIPT_NEWA: ch = 0x1140eu; break; + /* Unicode-10.0 additions */ + case HB_SCRIPT_SOYOMBO: ch = 0x11a5cu; break; + case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break; + /* Unicode-11.0 additions */ + case HB_SCRIPT_DOGRA: ch = 0x1180au; break; + case HB_SCRIPT_GUNJALA_GONDI: ch = 0x11d6cu; break; + /* Unicode-12.0 additions */ + case HB_SCRIPT_NANDINAGARI: ch = 0x119b0u; break; + default: ch = 0; break; + } + + if (ch && + hb_font_get_nominal_glyph (font, ch, &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *coord = extents.y_bearing; + else + *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin + } + else + *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: + { + hb_position_t top, bottom; + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &bottom); + *coord = (top + bottom) / 2; + + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: + { + hb_position_t top, bottom; + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &bottom); + *coord = (top + bottom) / 2; + + } + break; + + case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE: + default: + *coord = 0; + break; + } } + #endif diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h index d47ba0fc92..4edddd9e0d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.h +++ b/thirdparty/harfbuzz/src/hb-ot-layout.h @@ -332,31 +332,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_set_t *glyphs_after, /* OUT. May be NULL */ hb_set_t *glyphs_output /* OUT. May be NULL */); -#ifdef HB_NOT_IMPLEMENTED -typedef struct -{ - const hb_codepoint_t *before, - unsigned int before_length, - const hb_codepoint_t *input, - unsigned int input_length, - const hb_codepoint_t *after, - unsigned int after_length, -} hb_ot_layout_glyph_sequence_t; - -typedef hb_bool_t -(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font, - hb_tag_t table_tag, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - void *user_data); - -HB_EXTERN void -Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face, - hb_tag_t table_tag, - unsigned int lookup_index, - hb_ot_layout_glyph_sequence_func_t callback, - void *user_data); -#endif /* Variations support */ @@ -411,19 +386,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, hb_set_t *glyphs); -#ifdef HB_NOT_IMPLEMENTED -/* Note: You better have GDEF when using this API, or marks won't do much. */ -HB_EXTERN hb_bool_t -Xhb_ot_layout_lookup_substitute (hb_font_t *font, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - unsigned int out_size, - hb_codepoint_t *glyphs_out, /* OUT */ - unsigned int *clusters_out, /* OUT */ - unsigned int *out_length /* OUT */); -#endif - - /* * GPOS */ @@ -431,15 +393,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t *font, HB_EXTERN hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face); -#ifdef HB_NOT_IMPLEMENTED -/* Note: You better have GDEF when using this API, or marks won't do much. */ -HB_EXTERN hb_bool_t -Xhb_ot_layout_lookup_position (hb_font_t *font, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - hb_glyph_position_t *positions /* IN / OUT */); -#endif - /* Optical 'size' feature info. Returns true if found. * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ HB_EXTERN hb_bool_t @@ -487,9 +440,11 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge, * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0 * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge, * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline, + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0 * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered. * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered. @@ -503,14 +458,19 @@ typedef enum { HB_OT_LAYOUT_BASELINE_TAG_HANGING = HB_TAG ('h','a','n','g'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT = HB_TAG ('i','c','f','b'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT = HB_TAG ('i','c','f','t'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL = HB_TAG ('I','c','f','c'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT = HB_TAG ('i','d','e','o'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL = HB_TAG ('I','d','c','e'), HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'), /*< private >*/ _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_layout_baseline_tag_t; +HB_EXTERN hb_ot_layout_baseline_tag_t +hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script); + HB_EXTERN hb_bool_t hb_ot_layout_get_baseline (hb_font_t *font, hb_ot_layout_baseline_tag_t baseline_tag, @@ -519,6 +479,14 @@ hb_ot_layout_get_baseline (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT. May be NULL. */); +HB_EXTERN void +hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT */); + HB_END_DECLS #endif /* HB_OT_LAYOUT_H */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh index 2c825e0c81..75bba0bc50 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh @@ -108,13 +108,17 @@ hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer, namespace OT { struct hb_ot_apply_context_t; - struct SubstLookup; struct hb_ot_layout_lookup_accelerator_t; +namespace Layout { +namespace GSUB { + struct SubstLookup; +} +} } HB_INTERNAL void hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, - const OT::SubstLookup &lookup, + const OT::Layout::GSUB::SubstLookup &lookup, const OT::hb_ot_layout_lookup_accelerator_t &accel); @@ -168,17 +172,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start) return start; } -static inline void -_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - /* unicode_props */ @@ -482,7 +475,8 @@ _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info) } static inline uint8_t -_hb_allocate_lig_id (hb_buffer_t *buffer) { +_hb_allocate_lig_id (hb_buffer_t *buffer) +{ uint8_t lig_id = buffer->next_serial () & 0x07; if (unlikely (!lig_id)) lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */ diff --git a/thirdparty/harfbuzz/src/hb-ot-map.cc b/thirdparty/harfbuzz/src/hb-ot-map.cc index 12ceea5785..f085c78ff8 100644 --- a/thirdparty/harfbuzz/src/hb-ot-map.cc +++ b/thirdparty/harfbuzz/src/hb-ot-map.cc @@ -117,7 +117,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, hb_mask_t mask, bool auto_zwnj, bool auto_zwj, - bool random) + bool random, + bool per_syllable) { unsigned int lookup_indices[32]; unsigned int offset, len; @@ -145,6 +146,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, lookup->auto_zwnj = auto_zwnj; lookup->auto_zwj = auto_zwj; lookup->random = random; + lookup->per_syllable = per_syllable; } offset += len; @@ -277,6 +279,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ); map->auto_zwj = !(info->flags & F_MANUAL_ZWJ); map->random = !!(info->flags & F_RANDOM); + map->per_syllable = !!(info->flags & F_PER_SYLLABLE); if ((info->flags & F_GLOBAL) && info->max_value == 1) { /* Uses the global bit */ map->shift = global_bit_shift; @@ -319,7 +322,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, m.features[i].mask, m.features[i].auto_zwnj, m.features[i].auto_zwj, - m.features[i].random); + m.features[i].random, + m.features[i].per_syllable); /* Sort lookups and merge duplicates */ if (last_num_lookups < m.lookups[table_index].length) diff --git a/thirdparty/harfbuzz/src/hb-ot-map.hh b/thirdparty/harfbuzz/src/hb-ot-map.hh index 5f2afae281..f1cbf752fc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-map.hh +++ b/thirdparty/harfbuzz/src/hb-ot-map.hh @@ -56,6 +56,7 @@ struct hb_ot_map_t unsigned int auto_zwnj : 1; unsigned int auto_zwj : 1; unsigned int random : 1; + unsigned int per_syllable : 1; int cmp (const hb_tag_t tag_) const { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; } @@ -66,6 +67,7 @@ struct hb_ot_map_t unsigned short auto_zwnj : 1; unsigned short auto_zwj : 1; unsigned short random : 1; + unsigned short per_syllable : 1; hb_mask_t mask; HB_INTERNAL static int cmp (const void *pa, const void *pb) @@ -183,7 +185,8 @@ enum hb_ot_map_feature_flags_t F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS, F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK, F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */ - F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */ + F_RANDOM = 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */ + F_PER_SYLLABLE = 0x0040u /* Contain lookup application to within syllable. */ }; HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t); @@ -237,7 +240,8 @@ struct hb_ot_map_builder_t hb_mask_t mask, bool auto_zwnj = true, bool auto_zwj = true, - bool random = false); + bool random = false, + bool per_syllable = false); struct feature_info_t { hb_tag_t tag; diff --git a/thirdparty/harfbuzz/src/hb-ot-math-table.hh b/thirdparty/harfbuzz/src/hb-ot-math-table.hh index 8d0b4317c3..d834d94371 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-math-table.hh @@ -369,6 +369,37 @@ struct MathKern return kernValue[i].get_x_value (font, this); } + unsigned int get_entries (unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; + const unsigned int entriesCount = heightCount + 1; + + if (entries_count) + { + unsigned int start = hb_min (start_offset, entriesCount); + unsigned int end = hb_min (start + *entries_count, entriesCount); + *entries_count = end - start; + + for (unsigned int i = 0; i < *entries_count; i++) { + unsigned int j = start + i; + + hb_position_t max_height; + if (j == heightCount) { + max_height = INT32_MAX; + } else { + max_height = correctionHeight[j].get_y_value (font, this); + } + + kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; + } + } + return entriesCount; + } + protected: HBUINT16 heightCount; UnsizedArrayOf<MathValueRecord> @@ -423,6 +454,24 @@ struct MathKernInfoRecord return (base+mathKern[idx]).get_value (correction_height, font); } + unsigned int get_kernings (hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font, + const void *base) const + { + unsigned int idx = kern; + if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { + if (entries_count) *entries_count = 0; + return 0; + } + return (base+mathKern[idx]).get_entries (start_offset, + entries_count, + kern_entries, + font); + } + protected: /* Offset to MathKern table for each corner - * from the beginning of MathKernInfo table. May be NULL. */ @@ -473,6 +522,22 @@ struct MathKernInfo return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); } + unsigned int get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + unsigned int index = (this+mathKernCoverage).get_coverage (glyph); + return mathKernInfoRecords[index].get_kernings (kern, + start_offset, + entries_count, + kern_entries, + font, + this); + } + protected: Offset16To<Coverage> mathKernCoverage; @@ -545,6 +610,19 @@ struct MathGlyphInfo hb_font_t *font) const { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } + hb_position_t get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { return (this+mathKernInfo).get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); } + protected: /* Offset to MathItalicsCorrectionInfo table - * from the beginning of MathGlyphInfo table. */ diff --git a/thirdparty/harfbuzz/src/hb-ot-math.cc b/thirdparty/harfbuzz/src/hb-ot-math.cc index 5781d25f2a..f44ac35849 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math.cc +++ b/thirdparty/harfbuzz/src/hb-ot-math.cc @@ -185,6 +185,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, } /** + * hb_ot_math_get_glyph_kernings: + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the kernings + * @kern: The #hb_ot_math_kern_t from which to retrieve the kernings + * @start_offset: offset of the first kern entry to retrieve + * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return; + * Output = the actual number of kern entries returned + * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned + * + * Fetches the raw MathKern (cut-in) data for the specified font, glyph index, + * and @kern. The corresponding list of kern values and correction heights is + * returned as a list of #hb_ot_math_kern_entry_t structs. + * + * See also #hb_ot_math_get_glyph_kerning, which handles selecting the + * appropriate kern value for a given correction height. + * + * <note>For a glyph with @n defined kern values (where @n > 0), there are only + * @n−1 defined correction heights, as each correction height defines a boundary + * past which the next kern value should be selected. Therefore, only the + * #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t + * actually comes from the font; its corresponding + * #hb_ot_math_kern_entry_t.max_correction_height is always set to + * <code>INT32_MAX</code>.</note> + * + * Return value: the total number of kern values available or zero + * + * Since: 3.4.0 + **/ +unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */) +{ + return font->face->table.MATH->get_glyph_info().get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); +} + +/** * hb_ot_math_get_glyph_variants: * @font: #hb_font_t to work upon * @glyph: The index of the glyph to stretch diff --git a/thirdparty/harfbuzz/src/hb-ot-math.h b/thirdparty/harfbuzz/src/hb-ot-math.h index d3ffa19d85..1378a0639a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math.h +++ b/thirdparty/harfbuzz/src/hb-ot-math.h @@ -50,14 +50,18 @@ HB_BEGIN_DECLS #define HB_OT_TAG_MATH HB_TAG('M','A','T','H') /** - * HB_OT_MATH_SCRIPT: + * HB_OT_TAG_MATH_SCRIPT: * - * OpenType script tag for math shaping, for use with - * Use with hb_buffer_set_script(). + * OpenType script tag, `math`, for features specific to math shaping. * - * Since: 1.3.3 + * <note>#HB_OT_TAG_MATH_SCRIPT is not a valid #hb_script_t and should only be + * used with functions that accept raw OpenType script tags, such as + * #hb_ot_layout_collect_features. In other cases, #HB_SCRIPT_MATH should be + * used instead.</note> + * + * Since: 3.4.0 */ -#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h') +#define HB_OT_TAG_MATH_SCRIPT HB_TAG('m','a','t','h') /* Types */ @@ -205,6 +209,20 @@ typedef enum { } hb_ot_math_kern_t; /** + * hb_ot_math_kern_entry_t: + * @max_correction_height: The maximum height at which this entry should be used + * @kern_value: The kern value of the entry + * + * Data type to hold math kerning (cut-in) information for a glyph. + * + * Since: 3.4.0 + */ +typedef struct { + hb_position_t max_correction_height; + hb_position_t kern_value; +} hb_ot_math_kern_entry_t; + +/** * hb_ot_math_glyph_variant_t: * @glyph: The glyph index of the variant * @advance: The advance width of the variant @@ -281,6 +299,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, hb_position_t correction_height); HB_EXTERN unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */); + +HB_EXTERN unsigned int hb_ot_math_get_glyph_variants (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, diff --git a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh index e31447f8fc..93e64c5327 100644 --- a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh @@ -71,9 +71,9 @@ struct meta struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<meta> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_t *reference_entry (hb_tag_t tag) const { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); } @@ -119,7 +119,9 @@ struct meta DEFINE_SIZE_ARRAY (16, dataMaps); }; -struct meta_accelerator_t : meta::accelerator_t {}; +struct meta_accelerator_t : meta::accelerator_t { + meta_accelerator_t (hb_face_t *face) : meta::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.cc b/thirdparty/harfbuzz/src/hb-ot-metrics.cc index dbd4a1ffbe..f9c4b96fff 100644 --- a/thirdparty/harfbuzz/src/hb-ot-metrics.cc +++ b/thirdparty/harfbuzz/src/hb-ot-metrics.cc @@ -160,9 +160,50 @@ hb_ot_metrics_get_position (hb_font_t *font, (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); - case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise); - case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: return GET_METRIC_X (hhea, caretSlopeRun); + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: + { + unsigned mult = 1u; + + if (font->slant) + { + unsigned rise = face->table.hhea->caretSlopeRise; + unsigned upem = face->get_upem (); + mult = (rise && rise < upem) ? hb_min (upem / rise, 256u) : 1u; + } + + if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE) + { + bool ret = GET_METRIC_Y (hhea, caretSlopeRise); + + if (position) + *position *= mult; + + return ret; + } + else + { + hb_position_t rise = 0; + + if (font->slant && position && GET_METRIC_Y (hhea, caretSlopeRise)) + rise = *position; + + bool ret = GET_METRIC_X (hhea, caretSlopeRun); + + if (position) + { + *position *= mult; + + if (font->slant) + *position += _hb_roundf (mult * font->slant_xy * rise); + } + + return ret; + } + } case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset); + #ifndef HB_NO_VERTICAL case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise); case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun); @@ -197,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t *font, } } +/** + * hb_ot_metrics_get_position_with_fallback: + * @font: an #hb_font_t object. + * @metrics_tag: tag of metrics value you like to fetch. + * @position: (out) (optional): result of metrics value from the font. + * + * Fetches metrics value corresponding to @metrics_tag from @font, + * and synthesizes a value if it the value is missing in the font. + * + * Since: 4.0.0 + **/ +void +hb_ot_metrics_get_position_with_fallback (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT */) +{ + hb_font_extents_t font_extents; + hb_codepoint_t glyph; + hb_glyph_extents_t extents; + + if (hb_ot_metrics_get_position (font, metrics_tag, position)) + { + if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE && + metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) || + *position != 0) + return; + } + + switch (metrics_tag) + { + case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.descender; + break; + + case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.line_gap; + break; + + case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.line_gap; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: + case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: + *position = 1; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: + case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: + *position = 0; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: + case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: + *position = 0; + break; + + case HB_OT_METRICS_TAG_X_HEIGHT: + if (hb_font_get_nominal_glyph (font, 'x', &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *position = extents.y_bearing; + else + *position = font->y_scale / 2; + break; + + case HB_OT_METRICS_TAG_CAP_HEIGHT: + if (hb_font_get_nominal_glyph (font, 'O', &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *position = extents.height + 2 * extents.y_bearing; + else + *position = font->y_scale * 2 / 3; + break; + + case HB_OT_METRICS_TAG_STRIKEOUT_SIZE: + case HB_OT_METRICS_TAG_UNDERLINE_SIZE: + *position = font->y_scale / 18; + break; + + case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: + { + hb_position_t ascender; + hb_ot_metrics_get_position_with_fallback (font, + HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, + &ascender); + *position = ascender / 2; + } + break; + + case HB_OT_METRICS_TAG_UNDERLINE_OFFSET: + *position = - font->y_scale / 18; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: + *position = font->x_scale * 10 / 12; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: + *position = font->y_scale * 10 / 12; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: + *position = 0; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: + *position = font->y_scale / 5; + break; + + case _HB_OT_METRICS_TAG_MAX_VALUE: + default: + *position = 0; + break; + } +} + #ifndef HB_NO_VAR /** * hb_ot_metrics_get_variation: diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.h b/thirdparty/harfbuzz/src/hb-ot-metrics.h index 5841fc8b0f..30de500088 100644 --- a/thirdparty/harfbuzz/src/hb-ot-metrics.h +++ b/thirdparty/harfbuzz/src/hb-ot-metrics.h @@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag, hb_position_t *position /* OUT. May be NULL. */); +HB_EXTERN void +hb_ot_metrics_get_position_with_fallback (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT */); + HB_EXTERN float hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); diff --git a/thirdparty/harfbuzz/src/hb-ot-name-table.hh b/thirdparty/harfbuzz/src/hb-ot-name-table.hh index c17bb4abb8..d52367e9b1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-name-table.hh @@ -256,7 +256,7 @@ struct name }) ; - name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset)); + name_prime->serialize (c->serializer, it, std::addressof (this + stringOffset)); return_trace (name_prime->count); } @@ -279,7 +279,7 @@ struct name struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<name> (face); assert (this->table.get_length () >= this->table->stringOffset); @@ -288,7 +288,6 @@ struct name const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ, this->table->count); - this->names.init (); this->names.alloc (all_names.length); for (unsigned int i = 0; i < all_names.length; i++) @@ -318,10 +317,8 @@ struct name } this->names.resize (j); } - - void fini () + ~accelerator_t () { - this->names.fini (); this->table.destroy (); } @@ -373,7 +370,9 @@ struct name #undef entry_index #undef entry_score -struct name_accelerator_t : name::accelerator_t {}; +struct name_accelerator_t : name::accelerator_t { + name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-name.cc b/thirdparty/harfbuzz/src/hb-ot-name.cc index eff46ef227..c35ac5b3dc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name.cc +++ b/thirdparty/harfbuzz/src/hb-ot-name.cc @@ -52,7 +52,7 @@ * array is owned by the @face and should not be modified. It can be * used as long as @face is alive. * - * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries. + * Returns: (transfer none) (array length=num_entries): Array of available name entries. * Since: 2.1.0 **/ const hb_ot_name_entry_t * diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh index 504de2de74..0f3cd8e24f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh @@ -76,8 +76,7 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const hb_map_t old_new_index_map, old_gid_new_index_map; unsigned i = 0; - post::accelerator_t _post; - _post.init (c->plan->source); + post::accelerator_t _post (c->plan->source); hb_hashmap_t<hb_bytes_t, unsigned, std::nullptr_t, unsigned, nullptr, (unsigned)-1> glyph_name_to_new_index; for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) @@ -128,9 +127,7 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const }) ; - bool ret = serialize (c->serializer, index_iter, &_post); - _post.fini (); - return_trace (ret); + return_trace (serialize (c->serializer, index_iter, &_post)); } } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh index 39de671707..a4844e94bc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh @@ -111,10 +111,9 @@ struct post struct accelerator_t { friend struct postV2Tail; - void init (hb_face_t *face) - { - index_to_offset.init (); + accelerator_t (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table<post> (face); unsigned int table_length = table.get_length (); @@ -132,9 +131,8 @@ struct post data += 1 + *data) index_to_offset.push (data - pool); } - void fini () + ~accelerator_t () { - index_to_offset.fini (); hb_free (gids_sorted_by_name.get ()); table.destroy (); } @@ -254,9 +252,9 @@ struct post private: uint32_t version; - const Array16Of<HBUINT16> *glyphNameIndex; + const Array16Of<HBUINT16> *glyphNameIndex = nullptr; hb_vector_t<uint32_t> index_to_offset; - const uint8_t *pool; + const uint8_t *pool = nullptr; hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name; }; @@ -307,7 +305,10 @@ struct post DEFINE_SIZE_MIN (32); }; -struct post_accelerator_t : post::accelerator_t {}; +struct post_accelerator_t : post::accelerator_t { + post_accelerator_t (hb_face_t *face) : post::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh index 41e3dd38ab..429974d05b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh @@ -87,6 +87,8 @@ #define OT_GLYPHID /* GlyphID */ \ OT_UINT16 +/* Shorthand. */ +#define G OT_GLYPHID #define OT_UARRAY(Name, Items) \ OT_LABEL_START(Name) \ @@ -183,8 +185,6 @@ Tag \ OT_OFFSET(manifest, Name) -/* Shorthand. */ -#define G OT_GLYPHID /* * Table Start @@ -300,14 +300,40 @@ OT_TABLE_END /* * Clean up */ + +#undef MANIFEST +#undef MANIFEST_LOOKUP + #undef OT_TABLE_START #undef OT_TABLE_END #undef OT_LABEL_START #undef OT_LABEL_END #undef OT_UINT8 #undef OT_UINT16 -#undef OT_DISTANCE #undef OT_COUNT +#undef OT_DISTANCE + +#undef OT_LABEL +#undef OT_LIST + +#undef OT_TAG +#undef OT_OFFSET +#undef OT_GLYPHID +#undef G +#undef OT_UARRAY +#undef OT_UHEADLESSARRAY + +#undef OT_LOOKUP_FLAG_IGNORE_MARKS +#undef OT_LOOKUP +#undef OT_SUBLOOKUP +#undef OT_COVERAGE1 +#undef OT_LOOKUP_TYPE_SUBST_SINGLE +#undef OT_LOOKUP_TYPE_SUBST_LIGATURE +#undef OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2 +#undef OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1 +#undef OT_LIGATURE_SET +#undef OT_LIGATURE + /* * Include a second time to get the table data... diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc index 222c5d6b71..224f8b842e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc @@ -321,6 +321,20 @@ arabic_joining (hb_buffer_t *buffer) info[prev].arabic_shaping_action() = entry->prev_action; buffer->unsafe_to_break (prev, i + 1); } + else + { + if (prev == UINT_MAX) + { + if (this_type >= JOINING_TYPE_R) + buffer->unsafe_to_concat_from_outbuffer (0, i + 1); + } + else + { + if (this_type >= JOINING_TYPE_R || + (2 <= state && state <= 5) /* States that have a possible prev_action. */) + buffer->unsafe_to_concat (prev, i + 1); + } + } info[i].arabic_shaping_action() = entry->curr_action; @@ -337,7 +351,14 @@ arabic_joining (hb_buffer_t *buffer) const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; if (entry->prev_action != NONE && prev != UINT_MAX) + { info[prev].arabic_shaping_action() = entry->prev_action; + buffer->unsafe_to_break (prev, buffer->len); + } + else if (2 <= state && state <= 5) /* States that have a possible prev_action. */ + { + buffer->unsafe_to_concat (prev, buffer->len); + } break; } } @@ -614,6 +635,11 @@ modifier_combining_marks[] = 0x06E3u, /* ARABIC SMALL LOW SEEN */ 0x06E7u, /* ARABIC SMALL HIGH YEH */ 0x06E8u, /* ARABIC SMALL HIGH NOON */ + 0x08CAu, /* ARABIC SMALL HIGH FARSI YEH */ + 0x08CBu, /* ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW */ + 0x08CDu, /* ARABIC SMALL HIGH ZAH */ + 0x08CEu, /* ARABIC LARGE ROUND DOT ABOVE */ + 0x08CFu, /* ARABIC LARGE ROUND DOT BELOW */ 0x08D3u, /* ARABIC SMALL LOW WAW */ 0x08F3u, /* ARABIC SMALL HIGH WAW */ }; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc index 0d84a76b85..3bc9e9b961 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc @@ -140,7 +140,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, * * - LV can be precomposed, or decomposed. Lets call those * <LV> and <L,V>, - * - LVT can be fully precomposed, partically precomposed, or + * - LVT can be fully precomposed, partially precomposed, or * fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>. * * The composition / decomposition is mechanical. However, not @@ -392,7 +392,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, */ (void) buffer->next_glyph (); } - buffer->swap_buffers (); + buffer->sync (); } static void diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc index 4a8781c8f8..c80f7df6a9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc @@ -109,17 +109,17 @@ indic_features[] = * These features are applied in order, one at a time, after initial_reordering, * constrained to the syllable. */ - {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS}, - {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, - {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, - {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, - {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS}, - {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, - {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, /* * Other features. * These features are applied all at once, after final_reordering, constrained @@ -127,12 +127,12 @@ indic_features[] = * Default Bengali font in Windows for example has intermixed * lookups for init,pres,abvs,blws features. */ - {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS}, - {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, - {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE}, }; /* @@ -183,10 +183,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables_indic); - map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE); unsigned int i = 0; @@ -201,8 +201,6 @@ collect_features_indic (hb_ot_shape_planner_t *plan) for (; i < INDIC_NUM_FEATURES; i++) map->add_feature (indic_features[i]); - - map->add_gsub_pause (_hb_clear_syllables); } static void diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh index dcb28a4e84..da77a2887c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh @@ -368,6 +368,7 @@ set_indic_properties (hb_glyph_info_t &info) else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */ else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */ else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */ + else if (unlikely (u == 0x0D04u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/3511 */ else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u))) cat = OT_PLACEHOLDER; else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc index 7787886857..a7d5bf574b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc @@ -45,11 +45,11 @@ khmer_features[] = * These features are applied all at once, before reordering, constrained * to the syllable. */ - {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, - {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, - {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, - {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, - {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, + {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE}, /* * Other features. * These features are applied all at once after clearing syllables. @@ -107,14 +107,15 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) * * https://github.com/harfbuzz/harfbuzz/issues/974 */ - map->enable_feature (HB_TAG('l','o','c','l')); - map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE); + map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE); unsigned int i = 0; for (; i < KHMER_BASIC_FEATURES; i++) map->add_feature (khmer_features[i]); - map->add_gsub_pause (_hb_clear_syllables); + /* https://github.com/harfbuzz/harfbuzz/issues/3531 */ + map->add_gsub_pause (nullptr); for (; i < KHMER_NUM_FEATURES; i++) map->add_feature (khmer_features[i]); diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc index e6ae75e8f2..13beaf4d4c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc @@ -79,22 +79,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables_myanmar); - map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE); map->add_gsub_pause (reorder_myanmar); for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++) { - map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ); + map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (nullptr); } - map->add_gsub_pause (_hb_clear_syllables); - for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++) map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ); } @@ -107,8 +105,7 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category); HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position); - /* We cannot setup masks here. We save information about characters - * and setup masks later on in a pause-callback. */ + /* No masks, we just save information about characters. */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc index 5a08f878dc..76092c7f38 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc @@ -96,7 +96,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, else (void) buffer->next_glyph (); } - buffer->swap_buffers (); + buffer->sync (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc index 4c3068173b..a1e27a83be 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc @@ -364,7 +364,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, buffer->merge_out_clusters (start - 1, end); } } - buffer->swap_buffers (); + buffer->sync (); /* If font has Thai GSUB, we are done. */ if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0]) diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh index c3920b2cc6..468bd95c3f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh @@ -69,7 +69,7 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_GB 5u #define use_syllable_machine_ex_H 12u #define use_syllable_machine_ex_HN 13u -#define use_syllable_machine_ex_HVM 44u +#define use_syllable_machine_ex_IS 44u #define use_syllable_machine_ex_J 50u #define use_syllable_machine_ex_MAbv 27u #define use_syllable_machine_ex_MBlw 28u @@ -92,234 +92,449 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_VMPst 39u #define use_syllable_machine_ex_VPre 22u #define use_syllable_machine_ex_VPst 35u +#define use_syllable_machine_ex_WJ 16u #define use_syllable_machine_ex_ZWNJ 14u -#line 99 "hb-ot-shape-complex-use-machine.hh" +#line 100 "hb-ot-shape-complex-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 0u, 51u, 41u, 42u, 42u, 42u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 23u, 48u, + 0u, 51u, 11u, 48u, 11u, 48u, 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, + 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, + 23u, 48u, 23u, 48u, 23u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, + 1u, 1u, 11u, 48u, 41u, 42u, 42u, 42u, 11u, 48u, 11u, 48u, 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, - 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, - 11u, 48u, 1u, 48u, 13u, 13u, 4u, 4u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, - 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, - 24u, 48u, 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, - 22u, 48u, 11u, 48u, 1u, 48u, 4u, 4u, 13u, 13u, 1u, 48u, 11u, 48u, 41u, 42u, - 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, 0 + 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 12u, 48u, 12u, 48u, + 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 13u, 13u, 4u, 4u, 11u, 48u, 11u, 48u, + 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, + 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, + 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 11u, 48u, 11u, 48u, + 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, + 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, + 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 4u, 4u, 13u, 13u, + 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, + 0 }; static const char _use_syllable_machine_key_spans[] = { - 52, 2, 1, 38, 38, 1, 27, 26, + 52, 38, 38, 48, 26, 24, 23, 22, + 2, 1, 25, 25, 25, 1, 25, 27, + 26, 26, 26, 37, 37, 37, 37, 38, + 1, 38, 2, 1, 38, 38, 48, 26, 24, 23, 22, 2, 1, 25, 25, 25, - 1, 25, 26, 26, 26, 27, 27, 27, - 38, 48, 1, 1, 38, 38, 1, 27, - 26, 24, 23, 22, 2, 1, 25, 25, - 25, 1, 25, 26, 26, 26, 27, 27, - 27, 38, 48, 1, 1, 48, 38, 2, - 1, 5, 3, 4, 3 + 1, 25, 27, 26, 26, 26, 37, 37, + 37, 37, 38, 1, 1, 1, 38, 38, + 48, 26, 24, 23, 22, 2, 1, 25, + 25, 25, 1, 25, 27, 26, 26, 26, + 37, 37, 37, 37, 38, 1, 38, 38, + 48, 26, 24, 23, 22, 2, 1, 25, + 25, 25, 1, 25, 27, 26, 26, 26, + 37, 37, 37, 37, 38, 1, 1, 1, + 48, 38, 2, 1, 5, 3, 4, 3 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 53, 56, 58, 97, 136, 138, 166, - 193, 218, 242, 265, 268, 270, 296, 322, - 348, 350, 376, 403, 430, 457, 485, 513, - 541, 580, 629, 631, 633, 672, 711, 713, - 741, 768, 793, 817, 840, 843, 845, 871, - 897, 923, 925, 951, 978, 1005, 1032, 1060, - 1088, 1116, 1155, 1204, 1206, 1208, 1257, 1296, - 1299, 1301, 1307, 1311, 1316 + 0, 53, 92, 131, 180, 207, 232, 256, + 279, 282, 284, 310, 336, 362, 364, 390, + 418, 445, 472, 499, 537, 575, 613, 651, + 690, 692, 731, 734, 736, 775, 814, 863, + 890, 915, 939, 962, 965, 967, 993, 1019, + 1045, 1047, 1073, 1101, 1128, 1155, 1182, 1220, + 1258, 1296, 1334, 1373, 1375, 1377, 1379, 1418, + 1457, 1506, 1533, 1558, 1582, 1605, 1608, 1610, + 1636, 1662, 1688, 1690, 1716, 1744, 1771, 1798, + 1825, 1863, 1901, 1939, 1977, 2016, 2018, 2057, + 2096, 2145, 2172, 2197, 2221, 2244, 2247, 2249, + 2275, 2301, 2327, 2329, 2355, 2383, 2410, 2437, + 2464, 2502, 2540, 2578, 2616, 2655, 2657, 2659, + 2661, 2710, 2749, 2752, 2754, 2760, 2764, 2769 }; static const char _use_syllable_machine_indicies[] = { 0, 1, 2, 2, 3, 4, 2, 2, 2, 2, 2, 5, 6, 7, 2, 2, 2, 2, 8, 2, 2, 2, 9, 10, - 11, 12, 13, 14, 15, 9, 16, 17, - 18, 19, 20, 21, 2, 22, 23, 24, - 2, 25, 26, 27, 28, 29, 30, 31, - 6, 32, 2, 33, 2, 0, 35, 34, - 35, 34, 37, 38, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 39, 40, 41, - 42, 43, 44, 45, 39, 46, 1, 47, - 48, 49, 50, 36, 51, 52, 53, 36, - 36, 36, 36, 54, 55, 56, 57, 38, - 36, 37, 38, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 39, 40, 41, 42, - 43, 44, 45, 39, 46, 47, 47, 48, - 49, 50, 36, 51, 52, 53, 36, 36, - 36, 36, 54, 55, 56, 57, 38, 36, - 37, 58, 39, 40, 41, 42, 43, 36, - 36, 36, 36, 36, 36, 48, 49, 50, - 36, 51, 52, 53, 36, 36, 36, 36, - 40, 55, 56, 57, 59, 36, 40, 41, - 42, 43, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 51, 52, 53, 36, - 36, 36, 36, 36, 55, 56, 57, 59, - 36, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 55, 56, - 57, 36, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 55, 56, - 57, 36, 43, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 55, 56, 57, - 36, 55, 56, 36, 56, 36, 41, 42, - 43, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 51, 52, 53, 36, 36, - 36, 36, 36, 55, 56, 57, 59, 36, - 41, 42, 43, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 52, 53, - 36, 36, 36, 36, 36, 55, 56, 57, - 59, 36, 41, 42, 43, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 53, 36, 36, 36, 36, 36, 55, - 56, 57, 59, 36, 61, 60, 41, 42, - 43, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 55, 56, 57, 59, 36, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 48, 49, 50, 36, 51, 52, - 53, 36, 36, 36, 36, 40, 55, 56, - 57, 59, 36, 40, 41, 42, 43, 36, - 36, 36, 36, 36, 36, 36, 49, 50, - 36, 51, 52, 53, 36, 36, 36, 36, - 40, 55, 56, 57, 59, 36, 40, 41, - 42, 43, 36, 36, 36, 36, 36, 36, - 36, 36, 50, 36, 51, 52, 53, 36, - 36, 36, 36, 40, 55, 56, 57, 59, - 36, 39, 40, 41, 42, 43, 36, 45, - 39, 36, 36, 36, 48, 49, 50, 36, - 51, 52, 53, 36, 36, 36, 36, 40, - 55, 56, 57, 59, 36, 39, 40, 41, - 42, 43, 36, 36, 39, 36, 36, 36, - 48, 49, 50, 36, 51, 52, 53, 36, - 36, 36, 36, 40, 55, 56, 57, 59, - 36, 39, 40, 41, 42, 43, 44, 45, - 39, 36, 36, 36, 48, 49, 50, 36, - 51, 52, 53, 36, 36, 36, 36, 40, - 55, 56, 57, 59, 36, 37, 38, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 39, 40, 41, 42, 43, 44, 45, 39, - 46, 36, 47, 48, 49, 50, 36, 51, - 52, 53, 36, 36, 36, 36, 54, 55, - 56, 57, 38, 36, 37, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 40, 41, 42, 43, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, - 51, 52, 53, 58, 58, 58, 58, 58, - 55, 56, 57, 59, 58, 63, 62, 3, - 64, 37, 38, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 39, 40, 41, 42, - 43, 44, 45, 39, 46, 1, 47, 48, - 49, 50, 36, 51, 52, 53, 36, 0, - 35, 36, 54, 55, 56, 57, 38, 36, - 5, 6, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 9, 10, 11, 12, 13, - 14, 15, 9, 16, 18, 18, 19, 20, - 21, 65, 22, 23, 24, 65, 65, 65, - 65, 28, 29, 30, 31, 6, 65, 5, - 65, 9, 10, 11, 12, 13, 65, 65, - 65, 65, 65, 65, 19, 20, 21, 65, - 22, 23, 24, 65, 65, 65, 65, 10, - 29, 30, 31, 66, 65, 10, 11, 12, - 13, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 22, 23, 24, 65, 65, - 65, 65, 65, 29, 30, 31, 66, 65, - 11, 12, 13, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 29, 30, 31, - 65, 12, 13, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 29, 30, 31, - 65, 13, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 29, 30, 31, 65, - 29, 30, 65, 30, 65, 11, 12, 13, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 22, 23, 24, 65, 65, 65, - 65, 65, 29, 30, 31, 66, 65, 11, - 12, 13, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 23, 24, 65, - 65, 65, 65, 65, 29, 30, 31, 66, - 65, 11, 12, 13, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 24, 65, 65, 65, 65, 65, 29, 30, - 31, 66, 65, 67, 65, 11, 12, 13, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 29, 30, 31, 66, 65, 10, - 11, 12, 13, 65, 65, 65, 65, 65, - 65, 19, 20, 21, 65, 22, 23, 24, - 65, 65, 65, 65, 10, 29, 30, 31, - 66, 65, 10, 11, 12, 13, 65, 65, - 65, 65, 65, 65, 65, 20, 21, 65, - 22, 23, 24, 65, 65, 65, 65, 10, - 29, 30, 31, 66, 65, 10, 11, 12, - 13, 65, 65, 65, 65, 65, 65, 65, - 65, 21, 65, 22, 23, 24, 65, 65, - 65, 65, 10, 29, 30, 31, 66, 65, - 9, 10, 11, 12, 13, 65, 15, 9, - 65, 65, 65, 19, 20, 21, 65, 22, - 23, 24, 65, 65, 65, 65, 10, 29, - 30, 31, 66, 65, 9, 10, 11, 12, - 13, 65, 65, 9, 65, 65, 65, 19, - 20, 21, 65, 22, 23, 24, 65, 65, - 65, 65, 10, 29, 30, 31, 66, 65, - 9, 10, 11, 12, 13, 14, 15, 9, - 65, 65, 65, 19, 20, 21, 65, 22, - 23, 24, 65, 65, 65, 65, 10, 29, - 30, 31, 66, 65, 5, 6, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 9, - 10, 11, 12, 13, 14, 15, 9, 16, - 65, 18, 19, 20, 21, 65, 22, 23, - 24, 65, 65, 65, 65, 28, 29, 30, - 31, 6, 65, 5, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 10, 11, 12, 13, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 22, - 23, 24, 65, 65, 65, 65, 65, 29, - 30, 31, 66, 65, 68, 65, 7, 65, - 1, 65, 65, 65, 1, 65, 65, 65, - 65, 65, 5, 6, 7, 65, 65, 65, - 65, 65, 65, 65, 65, 9, 10, 11, - 12, 13, 14, 15, 9, 16, 17, 18, - 19, 20, 21, 65, 22, 23, 24, 65, - 25, 26, 65, 28, 29, 30, 31, 6, - 65, 5, 6, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 9, 10, 11, 12, - 13, 14, 15, 9, 16, 17, 18, 19, - 20, 21, 65, 22, 23, 24, 65, 65, - 65, 65, 28, 29, 30, 31, 6, 65, - 25, 26, 65, 26, 65, 1, 69, 69, - 69, 1, 69, 71, 70, 32, 70, 32, - 71, 70, 71, 70, 32, 70, 33, 70, - 0 + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 2, 23, 24, 25, + 2, 26, 27, 28, 29, 30, 31, 32, + 29, 33, 2, 34, 2, 36, 37, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 35, 52, + 53, 54, 35, 55, 56, 35, 57, 58, + 59, 60, 57, 35, 36, 37, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 48, 48, 49, 50, 51, 35, 52, 53, + 54, 35, 35, 35, 35, 57, 58, 59, + 60, 57, 35, 36, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 39, 40, 41, 42, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 52, + 53, 54, 35, 35, 35, 35, 35, 58, + 59, 60, 61, 35, 39, 40, 41, 42, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 52, 53, 54, 35, 35, 35, + 35, 35, 58, 59, 60, 61, 35, 40, + 41, 42, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 58, 59, 60, 35, + 41, 42, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 58, 59, 60, 35, + 42, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 58, 59, 60, 35, 58, + 59, 35, 59, 35, 40, 41, 42, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 52, 53, 54, 35, 35, 35, 35, + 35, 58, 59, 60, 61, 35, 40, 41, + 42, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 53, 54, 35, 35, + 35, 35, 35, 58, 59, 60, 61, 35, + 40, 41, 42, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 54, + 35, 35, 35, 35, 35, 58, 59, 60, + 61, 35, 62, 35, 40, 41, 42, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 58, 59, 60, 61, 35, 38, 39, + 40, 41, 42, 35, 35, 35, 35, 35, + 35, 49, 50, 51, 35, 52, 53, 54, + 35, 35, 35, 35, 35, 58, 59, 60, + 61, 35, 39, 40, 41, 42, 35, 35, + 35, 35, 35, 35, 49, 50, 51, 35, + 52, 53, 54, 35, 35, 35, 35, 35, + 58, 59, 60, 61, 35, 39, 40, 41, + 42, 35, 35, 35, 35, 35, 35, 35, + 50, 51, 35, 52, 53, 54, 35, 35, + 35, 35, 35, 58, 59, 60, 61, 35, + 39, 40, 41, 42, 35, 35, 35, 35, + 35, 35, 35, 35, 51, 35, 52, 53, + 54, 35, 35, 35, 35, 35, 58, 59, + 60, 61, 35, 39, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 38, 39, 40, + 41, 42, 35, 44, 45, 35, 35, 35, + 49, 50, 51, 35, 52, 53, 54, 35, + 35, 35, 35, 35, 58, 59, 60, 61, + 35, 39, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 38, 39, 40, 41, 42, + 35, 35, 45, 35, 35, 35, 49, 50, + 51, 35, 52, 53, 54, 35, 35, 35, + 35, 35, 58, 59, 60, 61, 35, 39, + 35, 35, 35, 35, 35, 35, 35, 35, + 35, 38, 39, 40, 41, 42, 35, 35, + 35, 35, 35, 35, 49, 50, 51, 35, + 52, 53, 54, 35, 35, 35, 35, 35, + 58, 59, 60, 61, 35, 39, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 38, + 39, 40, 41, 42, 43, 44, 45, 35, + 35, 35, 49, 50, 51, 35, 52, 53, + 54, 35, 35, 35, 35, 35, 58, 59, + 60, 61, 35, 36, 37, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 35, + 48, 49, 50, 51, 35, 52, 53, 54, + 35, 35, 35, 35, 57, 58, 59, 60, + 57, 35, 36, 35, 36, 37, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 35, 52, 53, + 54, 35, 35, 35, 35, 57, 58, 59, + 60, 57, 35, 55, 56, 35, 56, 35, + 64, 65, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 1, 75, 76, 77, + 78, 63, 79, 80, 81, 63, 63, 63, + 63, 82, 83, 84, 85, 86, 63, 64, + 65, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 75, 76, 77, 78, + 63, 79, 80, 81, 63, 63, 63, 63, + 82, 83, 84, 85, 86, 63, 64, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 67, 68, 69, 70, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 79, 80, 81, 63, 63, 63, + 63, 63, 83, 84, 85, 87, 63, 67, + 68, 69, 70, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 79, 80, 81, + 63, 63, 63, 63, 63, 83, 84, 85, + 87, 63, 68, 69, 70, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 83, + 84, 85, 63, 69, 70, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 83, + 84, 85, 63, 70, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 83, 84, + 85, 63, 83, 84, 63, 84, 63, 68, + 69, 70, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 79, 80, 81, 63, + 63, 63, 63, 63, 83, 84, 85, 87, + 63, 68, 69, 70, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 80, + 81, 63, 63, 63, 63, 63, 83, 84, + 85, 87, 63, 68, 69, 70, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 81, 63, 63, 63, 63, 63, + 83, 84, 85, 87, 63, 89, 88, 68, + 69, 70, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 83, 84, 85, 87, + 63, 66, 67, 68, 69, 70, 63, 63, + 63, 63, 63, 63, 76, 77, 78, 63, + 79, 80, 81, 63, 63, 63, 63, 63, + 83, 84, 85, 87, 63, 67, 68, 69, + 70, 63, 63, 63, 63, 63, 63, 76, + 77, 78, 63, 79, 80, 81, 63, 63, + 63, 63, 63, 83, 84, 85, 87, 63, + 67, 68, 69, 70, 63, 63, 63, 63, + 63, 63, 63, 77, 78, 63, 79, 80, + 81, 63, 63, 63, 63, 63, 83, 84, + 85, 87, 63, 67, 68, 69, 70, 63, + 63, 63, 63, 63, 63, 63, 63, 78, + 63, 79, 80, 81, 63, 63, 63, 63, + 63, 83, 84, 85, 87, 63, 67, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 66, 67, 68, 69, 70, 63, 72, 73, + 63, 63, 63, 76, 77, 78, 63, 79, + 80, 81, 63, 63, 63, 63, 63, 83, + 84, 85, 87, 63, 67, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 66, 67, + 68, 69, 70, 63, 63, 73, 63, 63, + 63, 76, 77, 78, 63, 79, 80, 81, + 63, 63, 63, 63, 63, 83, 84, 85, + 87, 63, 67, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 66, 67, 68, 69, + 70, 63, 63, 63, 63, 63, 63, 76, + 77, 78, 63, 79, 80, 81, 63, 63, + 63, 63, 63, 83, 84, 85, 87, 63, + 67, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 66, 67, 68, 69, 70, 71, + 72, 73, 63, 63, 63, 76, 77, 78, + 63, 79, 80, 81, 63, 63, 63, 63, + 63, 83, 84, 85, 87, 63, 64, 65, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 63, 75, 76, 77, 78, 63, + 79, 80, 81, 63, 63, 63, 63, 82, + 83, 84, 85, 86, 63, 64, 90, 92, + 91, 3, 93, 94, 95, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 63, 110, 111, 112, + 63, 55, 56, 63, 113, 114, 115, 85, + 116, 63, 94, 95, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 106, 106, + 107, 108, 109, 63, 110, 111, 112, 63, + 63, 63, 63, 113, 114, 115, 85, 116, + 63, 94, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 97, + 98, 99, 100, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 110, 111, 112, + 63, 63, 63, 63, 63, 114, 115, 85, + 117, 63, 97, 98, 99, 100, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 110, 111, 112, 63, 63, 63, 63, 63, + 114, 115, 85, 117, 63, 98, 99, 100, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 114, 115, 85, 63, 99, 100, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 114, 115, 85, 63, 100, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 114, 115, 85, 63, 114, 115, 63, + 115, 63, 98, 99, 100, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 110, + 111, 112, 63, 63, 63, 63, 63, 114, + 115, 85, 117, 63, 98, 99, 100, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 111, 112, 63, 63, 63, 63, + 63, 114, 115, 85, 117, 63, 98, 99, + 100, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 112, 63, 63, + 63, 63, 63, 114, 115, 85, 117, 63, + 118, 88, 98, 99, 100, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 114, + 115, 85, 117, 63, 96, 97, 98, 99, + 100, 63, 63, 63, 63, 63, 63, 107, + 108, 109, 63, 110, 111, 112, 63, 63, + 63, 63, 63, 114, 115, 85, 117, 63, + 97, 98, 99, 100, 63, 63, 63, 63, + 63, 63, 107, 108, 109, 63, 110, 111, + 112, 63, 63, 63, 63, 63, 114, 115, + 85, 117, 63, 97, 98, 99, 100, 63, + 63, 63, 63, 63, 63, 63, 108, 109, + 63, 110, 111, 112, 63, 63, 63, 63, + 63, 114, 115, 85, 117, 63, 97, 98, + 99, 100, 63, 63, 63, 63, 63, 63, + 63, 63, 109, 63, 110, 111, 112, 63, + 63, 63, 63, 63, 114, 115, 85, 117, + 63, 97, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 96, 97, 98, 99, 100, + 63, 102, 103, 63, 63, 63, 107, 108, + 109, 63, 110, 111, 112, 63, 63, 63, + 63, 63, 114, 115, 85, 117, 63, 97, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 96, 97, 98, 99, 100, 63, 63, + 103, 63, 63, 63, 107, 108, 109, 63, + 110, 111, 112, 63, 63, 63, 63, 63, + 114, 115, 85, 117, 63, 97, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 96, + 97, 98, 99, 100, 63, 63, 63, 63, + 63, 63, 107, 108, 109, 63, 110, 111, + 112, 63, 63, 63, 63, 63, 114, 115, + 85, 117, 63, 97, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 96, 97, 98, + 99, 100, 101, 102, 103, 63, 63, 63, + 107, 108, 109, 63, 110, 111, 112, 63, + 63, 63, 63, 63, 114, 115, 85, 117, + 63, 94, 95, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 63, 106, 107, + 108, 109, 63, 110, 111, 112, 63, 63, + 63, 63, 113, 114, 115, 85, 116, 63, + 94, 90, 94, 95, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 63, 110, 111, 112, 63, + 63, 63, 63, 113, 114, 115, 85, 116, + 63, 5, 6, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 19, 19, 20, + 21, 22, 119, 23, 24, 25, 119, 119, + 119, 119, 29, 30, 31, 32, 29, 119, + 5, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 10, 11, + 12, 13, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 23, 24, 25, 119, + 119, 119, 119, 119, 30, 31, 32, 120, + 119, 10, 11, 12, 13, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 23, + 24, 25, 119, 119, 119, 119, 119, 30, + 31, 32, 120, 119, 11, 12, 13, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 30, 31, 32, 119, 12, 13, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 30, 31, 32, 119, 13, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 30, 31, 32, 119, 30, 31, 119, 31, + 119, 11, 12, 13, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 23, 24, + 25, 119, 119, 119, 119, 119, 30, 31, + 32, 120, 119, 11, 12, 13, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 24, 25, 119, 119, 119, 119, 119, + 30, 31, 32, 120, 119, 11, 12, 13, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 25, 119, 119, 119, + 119, 119, 30, 31, 32, 120, 119, 121, + 119, 11, 12, 13, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 30, 31, + 32, 120, 119, 9, 10, 11, 12, 13, + 119, 119, 119, 119, 119, 119, 20, 21, + 22, 119, 23, 24, 25, 119, 119, 119, + 119, 119, 30, 31, 32, 120, 119, 10, + 11, 12, 13, 119, 119, 119, 119, 119, + 119, 20, 21, 22, 119, 23, 24, 25, + 119, 119, 119, 119, 119, 30, 31, 32, + 120, 119, 10, 11, 12, 13, 119, 119, + 119, 119, 119, 119, 119, 21, 22, 119, + 23, 24, 25, 119, 119, 119, 119, 119, + 30, 31, 32, 120, 119, 10, 11, 12, + 13, 119, 119, 119, 119, 119, 119, 119, + 119, 22, 119, 23, 24, 25, 119, 119, + 119, 119, 119, 30, 31, 32, 120, 119, + 10, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 9, 10, 11, 12, 13, 119, + 15, 16, 119, 119, 119, 20, 21, 22, + 119, 23, 24, 25, 119, 119, 119, 119, + 119, 30, 31, 32, 120, 119, 10, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 9, 10, 11, 12, 13, 119, 119, 16, + 119, 119, 119, 20, 21, 22, 119, 23, + 24, 25, 119, 119, 119, 119, 119, 30, + 31, 32, 120, 119, 10, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 9, 10, + 11, 12, 13, 119, 119, 119, 119, 119, + 119, 20, 21, 22, 119, 23, 24, 25, + 119, 119, 119, 119, 119, 30, 31, 32, + 120, 119, 10, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 9, 10, 11, 12, + 13, 14, 15, 16, 119, 119, 119, 20, + 21, 22, 119, 23, 24, 25, 119, 119, + 119, 119, 119, 30, 31, 32, 120, 119, + 5, 6, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 119, 19, 20, 21, + 22, 119, 23, 24, 25, 119, 119, 119, + 119, 29, 30, 31, 32, 29, 119, 5, + 119, 122, 119, 7, 119, 1, 119, 119, + 119, 1, 119, 119, 119, 119, 119, 5, + 6, 7, 119, 119, 119, 119, 119, 119, + 119, 119, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 119, 23, 24, 25, 119, 26, 27, 119, + 29, 30, 31, 32, 29, 119, 5, 6, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 119, + 23, 24, 25, 119, 119, 119, 119, 29, + 30, 31, 32, 29, 119, 26, 27, 119, + 27, 119, 1, 123, 123, 123, 1, 123, + 125, 124, 33, 124, 33, 125, 124, 125, + 124, 33, 124, 34, 124, 0 }; static const char _use_syllable_machine_trans_targs[] = { - 1, 3, 0, 26, 28, 29, 30, 51, - 53, 31, 32, 33, 34, 35, 46, 47, - 48, 54, 49, 43, 44, 45, 38, 39, - 40, 55, 56, 57, 50, 36, 37, 0, - 58, 60, 0, 2, 0, 4, 5, 6, - 7, 8, 9, 10, 21, 22, 23, 24, - 18, 19, 20, 13, 14, 15, 25, 11, - 12, 0, 0, 16, 0, 17, 0, 27, - 0, 0, 41, 42, 52, 0, 0, 59 + 1, 28, 0, 52, 54, 79, 80, 102, + 104, 92, 81, 82, 83, 84, 96, 97, + 98, 99, 105, 100, 93, 94, 95, 87, + 88, 89, 106, 107, 108, 101, 85, 86, + 0, 109, 111, 0, 2, 3, 15, 4, + 5, 6, 7, 19, 20, 21, 22, 25, + 23, 16, 17, 18, 10, 11, 12, 26, + 27, 24, 8, 9, 0, 13, 14, 0, + 29, 30, 42, 31, 32, 33, 34, 46, + 47, 48, 49, 50, 43, 44, 45, 37, + 38, 39, 51, 35, 36, 0, 51, 40, + 0, 41, 0, 0, 53, 0, 55, 56, + 68, 57, 58, 59, 60, 72, 73, 74, + 75, 78, 76, 69, 70, 71, 63, 64, + 65, 77, 61, 62, 77, 66, 67, 0, + 90, 91, 103, 0, 0, 110 }; static const char _use_syllable_machine_trans_actions[] = { 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4, - 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 7, 8, 0, 9, 0, 10, 0, - 11, 12, 0, 0, 0, 13, 14, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 0, 9, 10, 0, + 11, 0, 12, 13, 0, 14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 0, 10, 0, 0, 15, + 0, 0, 0, 16, 17, 0 }; static const char _use_syllable_machine_to_state_actions[] = { @@ -330,7 +545,13 @@ static const char _use_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; static const char _use_syllable_machine_from_state_actions[] = { @@ -341,18 +562,30 @@ static const char _use_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; static const short _use_syllable_machine_eof_trans[] = { - 0, 35, 35, 37, 37, 59, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 61, 37, 37, 37, 37, 37, 37, 37, - 37, 59, 63, 65, 37, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 70, 71, 71, 71 + 0, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 89, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 91, 92, 94, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 89, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 91, 64, 120, + 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 124, 125, 125, 125 }; static const int use_syllable_machine_start = 0; @@ -366,7 +599,7 @@ static const int use_syllable_machine_en_main = 0; -#line 179 "hb-ot-shape-complex-use-machine.rl" +#line 181 "hb-ot-shape-complex-use-machine.rl" #define found_syllable(syllable_type) \ @@ -385,7 +618,9 @@ struct machine_index_t : typename Iter::item_t> { machine_index_t (const Iter& it) : it (it) {} - machine_index_t (const machine_index_t& o) : it (o.it) {} + machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, + typename Iter::item_t> (), + it (o.it), is_null (o.is_null) {} static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; @@ -397,14 +632,28 @@ struct machine_index_t : void __forward__ (unsigned n) { it += n; } void __prev__ () { --it; } void __rewind__ (unsigned n) { it -= n; } + void operator = (unsigned n) - { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; } - void operator = (const machine_index_t& o) { *this = (*o.it).first; } - bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; } + { + assert (n == 0); + is_null = true; + } + explicit operator bool () { return !is_null; } + + void operator = (const machine_index_t& o) + { + is_null = o.is_null; + unsigned index = (*it).first; + unsigned n = (*o.it).first; + if (index < n) it += n - index; else if (index > n) it -= index - n; + } + bool operator == (const machine_index_t& o) const + { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; } bool operator != (const machine_index_t& o) const { return !(*this == o); } private: Iter it; + bool is_null = false; }; struct { @@ -420,7 +669,7 @@ HB_FUNCOBJ (machine_index); static bool not_ccs_default_ignorable (const hb_glyph_info_t &i) -{ return !(i.use_category() == USE(CGJ) && _hb_glyph_info_is_default_ignorable (&i)); } +{ return i.use_category() != USE(CGJ); } static inline void find_syllables_use (hb_buffer_t *buffer) @@ -449,7 +698,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int act HB_UNUSED; int cs; -#line 453 "hb-ot-shape-complex-use-machine.hh" +#line 702 "hb-ot-shape-complex-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -457,12 +706,12 @@ find_syllables_use (hb_buffer_t *buffer) act = 0; } -#line 263 "hb-ot-shape-complex-use-machine.rl" +#line 281 "hb-ot-shape-complex-use-machine.rl" unsigned int syllable_serial = 1; -#line 466 "hb-ot-shape-complex-use-machine.hh" +#line 715 "hb-ot-shape-complex-use-machine.hh" { int _slen; int _trans; @@ -476,7 +725,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 480 "hb-ot-shape-complex-use-machine.hh" +#line 729 "hb-ot-shape-complex-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -494,55 +743,79 @@ _eof_trans: goto _again; switch ( _use_syllable_machine_trans_actions[_trans] ) { - case 7: -#line 169 "hb-ot-shape-complex-use-machine.rl" + case 9: +#line 171 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (use_standard_cluster); }} break; - case 4: + case 6: #line 174 "hb-ot-shape-complex-use-machine.rl" + {te = p+1;{ found_syllable (use_symbol_cluster); }} + break; + case 4: +#line 176 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (use_broken_cluster); }} break; case 3: -#line 175 "hb-ot-shape-complex-use-machine.rl" +#line 177 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (use_non_cluster); }} break; - case 8: -#line 167 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }} - break; - case 9: -#line 168 "hb-ot-shape-complex-use-machine.rl" + case 11: +#line 170 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }} break; - case 6: -#line 169 "hb-ot-shape-complex-use-machine.rl" + case 7: +#line 171 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_standard_cluster); }} break; - case 11: -#line 170 "hb-ot-shape-complex-use-machine.rl" + case 14: +#line 172 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }} break; - case 10: -#line 171 "hb-ot-shape-complex-use-machine.rl" + case 13: +#line 173 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_numeral_cluster); }} break; case 5: -#line 172 "hb-ot-shape-complex-use-machine.rl" +#line 174 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_symbol_cluster); }} break; - case 14: -#line 173 "hb-ot-shape-complex-use-machine.rl" + case 17: +#line 175 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }} break; - case 12: -#line 174 "hb-ot-shape-complex-use-machine.rl" + case 15: +#line 176 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_broken_cluster); }} break; - case 13: -#line 175 "hb-ot-shape-complex-use-machine.rl" + case 16: +#line 177 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (use_non_cluster); }} break; -#line 546 "hb-ot-shape-complex-use-machine.hh" + case 12: +#line 1 "NONE" + { switch( act ) { + case 1: + {{p = ((te))-1;} found_syllable (use_virama_terminated_cluster); } + break; + case 2: + {{p = ((te))-1;} found_syllable (use_sakot_terminated_cluster); } + break; + } + } + break; + case 8: +#line 1 "NONE" + {te = p+1;} +#line 169 "hb-ot-shape-complex-use-machine.rl" + {act = 1;} + break; + case 10: +#line 1 "NONE" + {te = p+1;} +#line 170 "hb-ot-shape-complex-use-machine.rl" + {act = 2;} + break; +#line 819 "hb-ot-shape-complex-use-machine.hh" } _again: @@ -551,7 +824,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 555 "hb-ot-shape-complex-use-machine.hh" +#line 828 "hb-ot-shape-complex-use-machine.hh" } if ( ++p != pe ) @@ -567,7 +840,7 @@ _again: } -#line 268 "hb-ot-shape-complex-use-machine.rl" +#line 286 "hb-ot-shape-complex-use-machine.rl" } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh index 7a3a995c8c..c8e5151694 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh @@ -53,7 +53,7 @@ #define GB USE(GB) /* BASE_OTHER */ #define H USE(H) /* HALANT */ #define HN USE(HN) /* HALANT_NUM */ -#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */ +#define IS USE(IS) /* INVISIBLE_STACKER */ #define J USE(J) /* HIEROGLYPH_JOINER */ #define N USE(N) /* BASE_NUM */ #define O USE(O) /* OTHER */ @@ -62,6 +62,7 @@ #define SE USE(SE) /* HIEROGLYPH_SEGMENT_END */ #define SUB USE(SUB) /* CONS_SUB */ #define Sk USE(Sk) /* SAKOT */ +#define WJ USE(WJ) /* Word_Joiner */ #define ZWNJ USE(ZWNJ) /* ZWNJ */ #define CMAbv USE(CMAbv) #define CMBlw USE(CMBlw) @@ -102,7 +103,7 @@ static const uint8_t use_table[] = { /* Latin-1 Supplement */ - /* 00A0 */ GB, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 00A0 */ GB, O, O, O, O, O, O, O, O, O, O, O, O, WJ, O, O, /* 00B0 */ O, O, FMPst, FMPst, O, O, O, O, O, O, O, O, O, O, O, O, /* 00C0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 00D0 */ O, O, O, O, O, O, O, GB, @@ -127,7 +128,7 @@ static const uint8_t use_table[] = { O, O, B, B, B, B, B, B, /* 07D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 07E0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, - /* 07F0 */ VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, O, O, O, B, O, O, VMAbv, O, O, + /* 07F0 */ VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, O, O, O, B, WJ, WJ, VMAbv, O, O, #define use_offset_0x0840u 152 @@ -135,7 +136,7 @@ static const uint8_t use_table[] = { /* Mandaic */ /* 0840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0850 */ B, B, B, B, B, B, B, B, B, CMBlw, CMBlw, CMBlw, O, O, O, O, + /* 0850 */ B, B, B, B, B, B, B, B, B, CMBlw, CMBlw, CMBlw, WJ, WJ, O, WJ, #define use_offset_0x0900u 184 @@ -153,102 +154,102 @@ static const uint8_t use_table[] = { /* Bengali */ - /* 0980 */ GB, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B, - /* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre, - /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, - /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B, - /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FMAbv, O, + /* 0980 */ GB, VMAbv, VMPst, VMPst, WJ, B, B, B, B, B, B, B, B, WJ, WJ, B, + /* 0990 */ B, WJ, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 09A0 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 09B0 */ B, WJ, B, WJ, WJ, WJ, B, B, B, B, WJ, WJ, CMBlw, B, VPst, VPre, + /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, WJ, WJ, VPre, VPre, WJ, WJ, VPre, VPre, H, O, WJ, + /* 09D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, VPst, WJ, WJ, WJ, WJ, B, B, WJ, B, + /* 09E0 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FMAbv, WJ, /* Gurmukhi */ - /* 0A00 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, O, O, O, O, B, - /* 0A10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0A20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 0A30 */ B, O, B, B, O, B, B, O, B, B, O, O, CMBlw, O, VPst, VPre, - /* 0A40 */ VPst, VBlw, VBlw, O, O, O, O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O, - /* 0A50 */ O, VMBlw, O, O, O, O, O, O, O, B, B, B, B, O, B, O, - /* 0A60 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0A70 */ VMAbv, CMAbv, GB, GB, O, MBlw, O, O, O, O, O, O, O, O, O, O, + /* 0A00 */ WJ, VMAbv, VMAbv, VMPst, WJ, B, B, B, B, B, B, WJ, WJ, WJ, WJ, B, + /* 0A10 */ B, WJ, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0A20 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 0A30 */ B, WJ, B, B, WJ, B, B, WJ, B, B, WJ, WJ, CMBlw, WJ, VPst, VPre, + /* 0A40 */ VPst, VBlw, VBlw, WJ, WJ, WJ, WJ, VAbv, VAbv, WJ, WJ, VAbv, VAbv, H, WJ, WJ, + /* 0A50 */ WJ, VMBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, WJ, B, WJ, + /* 0A60 */ WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0A70 */ VMAbv, CMAbv, GB, GB, O, MBlw, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Gujarati */ - /* 0A80 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, B, O, B, - /* 0A90 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0AA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 0AB0 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPre, - /* 0AC0 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H, O, O, - /* 0AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 0AE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0AF0 */ O, O, O, O, O, O, O, O, O, B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv, + /* 0A80 */ WJ, VMAbv, VMAbv, VMPst, WJ, B, B, B, B, B, B, B, B, B, WJ, B, + /* 0A90 */ B, B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0AA0 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 0AB0 */ B, WJ, B, B, WJ, B, B, B, B, B, WJ, WJ, CMBlw, B, VPst, VPre, + /* 0AC0 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, WJ, VAbv, VAbv, VAbv, WJ, VPst, VPst, H, WJ, WJ, + /* 0AD0 */ O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 0AE0 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0AF0 */ O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv, /* Oriya */ - /* 0B00 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B, - /* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, - /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, - /* 0B50 */ O, O, O, O, O, VAbv, VAbv, VAbv, O, O, O, O, B, B, O, B, - /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 0B00 */ WJ, VMAbv, VMPst, VMPst, WJ, B, B, B, B, B, B, B, B, WJ, WJ, B, + /* 0B10 */ B, WJ, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0B20 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 0B30 */ B, WJ, B, B, WJ, B, B, B, B, B, WJ, WJ, CMBlw, B, VPst, VAbv, + /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, WJ, WJ, VPre, VPre, WJ, WJ, VPre, VPre, H, WJ, WJ, + /* 0B50 */ WJ, WJ, WJ, WJ, WJ, VAbv, VAbv, VAbv, WJ, WJ, WJ, WJ, B, B, WJ, B, + /* 0B60 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0B70 */ O, B, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Tamil */ - /* 0B80 */ O, O, VMAbv, O, O, B, B, B, B, B, B, O, O, O, B, B, - /* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B, - /* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B, - /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst, - /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O, - /* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O, - /* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 0B80 */ WJ, WJ, VMAbv, O, WJ, B, B, B, B, B, B, WJ, WJ, WJ, B, B, + /* 0B90 */ B, WJ, B, B, B, B, WJ, WJ, WJ, B, B, WJ, B, WJ, B, B, + /* 0BA0 */ WJ, WJ, WJ, B, B, WJ, WJ, WJ, B, B, B, WJ, WJ, WJ, B, B, + /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, VPst, VPst, + /* 0BC0 */ VAbv, VPst, VPst, WJ, WJ, WJ, VPre, VPre, VPre, WJ, VPre, VPre, VPre, H, WJ, WJ, + /* 0BD0 */ O, WJ, WJ, WJ, WJ, WJ, WJ, VPst, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 0BE0 */ WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, /* Telugu */ - /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, VMAbv, B, B, B, B, B, B, B, B, O, B, B, - /* 0C10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0C20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 0C30 */ B, B, B, B, B, B, B, B, B, B, O, O, CMBlw, B, VAbv, VAbv, - /* 0C40 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O, - /* 0C50 */ O, O, O, O, O, VAbv, VBlw, O, B, B, B, O, O, O, O, O, - /* 0C60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0C70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, VMAbv, B, B, B, B, B, B, B, B, WJ, B, B, + /* 0C10 */ B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0C20 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 0C30 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, CMBlw, B, VAbv, VAbv, + /* 0C40 */ VAbv, VPst, VPst, VPst, VPst, WJ, VAbv, VAbv, VAbv, WJ, VAbv, VAbv, VAbv, H, WJ, WJ, + /* 0C50 */ WJ, WJ, WJ, WJ, WJ, VAbv, VBlw, WJ, B, B, B, WJ, WJ, O, WJ, WJ, + /* 0C60 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0C70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, O, O, O, O, O, /* Kannada */ - /* 0C80 */ B, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B, - /* 0C90 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0CA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 0CB0 */ B, B, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, - /* 0CC0 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O, - /* 0CD0 */ O, O, O, O, O, VPst, VPst, O, O, O, O, O, O, O, B, O, - /* 0CE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0CF0 */ O, CS, CS, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 0C80 */ B, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, WJ, B, B, + /* 0C90 */ B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0CA0 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 0CB0 */ B, B, B, B, WJ, B, B, B, B, B, WJ, WJ, CMBlw, B, VPst, VAbv, + /* 0CC0 */ VAbv, VPst, VPst, VPst, VPst, WJ, VAbv, VAbv, VAbv, WJ, VAbv, VAbv, VAbv, H, WJ, WJ, + /* 0CD0 */ WJ, WJ, WJ, WJ, WJ, VPst, VPst, WJ, WJ, WJ, WJ, WJ, WJ, O, B, WJ, + /* 0CE0 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0CF0 */ WJ, CS, CS, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Malayalam */ - /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst, B, B, B, B, B, B, B, B, B, O, B, B, - /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst, B, B, B, B, B, B, B, B, B, WJ, B, B, + /* 0D10 */ B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst, - /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O, - /* 0D50 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, B, - /* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, + /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, WJ, VPre, VPre, VPre, WJ, VPre, VPre, VPre, H, R, O, + /* 0D50 */ WJ, WJ, WJ, WJ, O, O, O, VPst, O, O, O, O, O, O, O, B, + /* 0D60 */ B, B, VBlw, VBlw, WJ, WJ, B, B, B, B, B, B, B, B, B, B, /* 0D70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* Sinhala */ - /* 0D80 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, B, B, B, - /* 0D90 */ B, B, B, B, B, B, B, O, O, O, B, B, B, B, B, B, + /* 0D80 */ WJ, VMAbv, VMPst, VMPst, WJ, B, B, B, B, B, B, B, B, B, B, B, + /* 0D90 */ B, B, B, B, B, B, B, WJ, WJ, WJ, B, B, B, B, B, B, /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O, - /* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst, - /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, - /* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, - /* 0DF0 */ O, O, VPst, VPst, O, O, O, O, + /* 0DB0 */ B, B, WJ, B, B, B, B, B, B, B, B, B, WJ, B, WJ, WJ, + /* 0DC0 */ B, B, B, B, B, B, B, WJ, WJ, WJ, H, WJ, WJ, WJ, WJ, VPst, + /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, WJ, VBlw, WJ, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, + /* 0DE0 */ WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, B, B, B, B, B, B, + /* 0DF0 */ WJ, WJ, VPst, VPst, O, WJ, WJ, WJ, #define use_offset_0x0f00u 1456 @@ -259,14 +260,14 @@ static const uint8_t use_table[] = { /* 0F10 */ O, O, O, O, O, O, O, O, VBlw, VBlw, O, O, O, O, O, O, /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0F30 */ B, B, B, B, O, FBlw, O, FBlw, O, CMAbv, O, O, O, O, VPst, VPre, - /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B, + /* 0F40 */ B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, B, /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, - /* 0F70 */ O, CMBlw, VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, O, + /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, + /* 0F70 */ WJ, CMBlw, VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, O, /* 0F80 */ VBlw, VAbv, VMAbv, VMAbv, VBlw, O, VMAbv, VMAbv, B, B, B, B, B, SUB, SUB, SUB, - /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, WJ, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, - /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O, + /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, WJ, O, O, /* 0FC0 */ O, O, O, O, O, O, FBlw, O, #define use_offset_0x1000u 1656 @@ -277,7 +278,7 @@ static const uint8_t use_table[] = { /* 1000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1020 */ B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VAbv, VAbv, VBlw, - /* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, H, VAbv, MPst, MPre, MBlw, MBlw, B, + /* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, /* 1040 */ B, B, B, B, B, B, B, B, B, B, O, GB, O, O, GB, O, /* 1050 */ B, B, B, B, B, B, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw, /* 1060 */ MBlw, B, VPst, VMPst, VMPst, B, B, VPst, VPst, VMPst, VMPst, VMPst, VMPst, VMPst, B, B, @@ -291,22 +292,22 @@ static const uint8_t use_table[] = { /* Tagalog */ /* 1700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1710 */ B, B, VAbv, VBlw, VBlw, VPst, O, O, O, O, O, O, O, O, O, B, + /* 1710 */ B, B, VAbv, VBlw, VBlw, VPst, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, B, /* Hanunoo */ /* 1720 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1730 */ B, B, VAbv, VBlw, VPst, O, O, O, O, O, O, O, O, O, O, O, + /* 1730 */ B, B, VAbv, VBlw, VPst, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Buhid */ /* 1740 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1750 */ B, B, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1750 */ B, B, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Tagbanwa */ - /* 1760 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, B, B, - /* 1770 */ B, O, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1760 */ B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, B, B, + /* 1770 */ B, WJ, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Khmer */ @@ -315,23 +316,23 @@ static const uint8_t use_table[] = { /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 17B0 */ B, B, B, B, CGJ, CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre, /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FMAbv, FAbv, CMAbv, FMAbv, VMAbv, - /* 17D0 */ FMAbv, VAbv, H, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, O, O, - /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 17F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 17D0 */ FMAbv, VAbv, IS, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, WJ, WJ, + /* 17E0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, + /* 17F0 */ O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, /* Mongolian */ - /* 1800 */ B, O, O, O, O, O, O, B, O, O, B, CGJ, CGJ, CGJ, O, CGJ, - /* 1810 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1800 */ B, O, O, O, O, O, O, B, O, O, B, CGJ, CGJ, CGJ, WJ, CGJ, + /* 1810 */ O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, /* 1820 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1830 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1850 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1860 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1870 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, + /* 1870 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* 1880 */ GB, GB, GB, GB, GB, CMAbv, CMAbv, B, B, B, B, B, B, B, B, B, /* 1890 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 18A0 */ B, B, B, B, B, B, B, B, B, CMBlw, B, O, O, O, O, O, + /* 18A0 */ B, B, B, B, B, B, B, B, B, CMBlw, B, WJ, WJ, WJ, WJ, WJ, #define use_offset_0x1900u 2248 @@ -339,43 +340,43 @@ static const uint8_t use_table[] = { /* Limbu */ /* 1900 */ GB, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, - /* 1920 */ VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, O, O, O, O, - /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VMAbv, FMBlw, O, O, O, O, - /* 1940 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, + /* 1910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, + /* 1920 */ VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, WJ, WJ, WJ, WJ, + /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VMAbv, FMBlw, WJ, WJ, WJ, WJ, + /* 1940 */ O, WJ, WJ, WJ, O, O, B, B, B, B, B, B, B, B, B, B, /* Tai Le */ /* 1950 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1960 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, - /* 1970 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, + /* 1960 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, + /* 1970 */ B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* New Tai Lue */ /* 1980 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 19A0 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, + /* 19A0 */ B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, /* 19B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 19C0 */ B, B, B, B, B, B, B, B, VMPst, VMPst, O, O, O, O, O, O, - /* 19D0 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, + /* 19C0 */ B, B, B, B, B, B, B, B, VMPst, VMPst, WJ, WJ, WJ, WJ, WJ, WJ, + /* 19D0 */ B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, O, O, /* 19E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 19F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* Buginese */ /* 1A00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1A10 */ B, B, B, B, B, B, B, VAbv, VAbv, VPre, VPst, VAbv, O, O, O, O, + /* 1A10 */ B, B, B, B, B, B, B, VAbv, VAbv, VPre, VPst, VAbv, WJ, WJ, O, O, /* Tai Tham */ /* 1A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1A30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1A50 */ B, B, B, B, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, O, + /* 1A50 */ B, B, B, B, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, WJ, /* 1A60 */ Sk, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, - /* 1A70 */ VPre, VPre, VPre, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VAbv, VMAbv, VMAbv, O, O, VMBlw, - /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 1A70 */ VPre, VPre, VPre, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VAbv, VMAbv, VMAbv, WJ, WJ, VMBlw, + /* 1A80 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, + /* 1A90 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, #define use_offset_0x1b00u 2664 @@ -386,16 +387,16 @@ static const uint8_t use_table[] = { /* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, - /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, B, O, O, O, - /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, GB, GB, O, O, GB, - /* 1B60 */ O, O, GB, O, O, O, O, O, GB, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, - /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, B, WJ, WJ, WJ, + /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, + /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, WJ, /* Sundanese */ /* 1B80 */ VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, H, SUB, SUB, B, B, + /* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, IS, SUB, SUB, B, B, /* 1BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* Batak */ @@ -403,15 +404,15 @@ static const uint8_t use_table[] = { /* 1BC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1BD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1BE0 */ B, B, B, B, B, B, CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv, - /* 1BF0 */ FAbv, FAbv, CMBlw, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1BF0 */ FAbv, FAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, /* Lepcha */ /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, - /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, O, O, O, O, O, O, O, O, - /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, + /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, WJ, WJ, WJ, O, O, O, O, O, + /* 1C40 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, B, B, B, #define use_offset_0x1cd0u 3000 @@ -420,7 +421,7 @@ static const uint8_t use_table[] = { /* 1CD0 */ VMAbv, VMAbv, VMAbv, O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw, /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O, - /* 1CF0 */ O, O, O, O, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, GB, O, O, O, O, O, + /* 1CF0 */ O, O, O, O, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, GB, WJ, WJ, WJ, WJ, WJ, #define use_offset_0x1df8u 3048 @@ -432,31 +433,33 @@ static const uint8_t use_table[] = { /* General Punctuation */ - O, O, O, O, ZWNJ, CGJ, O, O, - /* 2010 */ GB, GB, GB, GB, GB, O, O, O, - -#define use_offset_0x2070u 3072 - + O, O, O, WJ, ZWNJ, CGJ, WJ, WJ, + /* 2010 */ GB, GB, GB, GB, GB, O, O, O, O, O, O, O, O, O, O, O, + /* 2020 */ O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, O, + /* 2030 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 2040 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 2050 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 2060 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Superscripts and Subscripts */ - /* 2070 */ O, O, O, O, FMPst, O, O, O, O, O, O, O, O, O, O, O, + /* 2070 */ O, O, WJ, WJ, FMPst, O, O, O, O, O, O, O, O, O, O, O, /* 2080 */ O, O, FMPst, FMPst, FMPst, O, O, O, -#define use_offset_0x20f0u 3096 +#define use_offset_0x20f0u 3184 /* Combining Diacritical Marks for Symbols */ - /* 20F0 */ VMAbv, O, O, O, O, O, O, O, + /* 20F0 */ VMAbv, WJ, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x25c8u 3104 +#define use_offset_0x25c8u 3192 /* Geometric Shapes */ O, O, O, O, B, O, O, O, -#define use_offset_0x2d30u 3112 +#define use_offset_0x2d30u 3200 /* Tifinagh */ @@ -464,25 +467,25 @@ static const uint8_t use_table[] = { /* 2D30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 2D40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 2D50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 2D60 */ B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, B, - /* 2D70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, H, + /* 2D60 */ B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, B, + /* 2D70 */ O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, H, -#define use_offset_0xa800u 3192 +#define use_offset_0xa800u 3280 /* Syloti Nagri */ /* A800 */ B, B, VAbv, B, B, B, H, B, B, B, B, VMAbv, B, B, B, B, /* A810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, VBlw, O, O, O, - /* A830 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, VBlw, WJ, WJ, WJ, + /* A830 */ O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, /* Phags-pa */ /* A840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A850 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A860 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* A870 */ B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, O, + /* A870 */ B, B, B, B, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Saurashtra */ @@ -490,8 +493,8 @@ static const uint8_t use_table[] = { /* A890 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A8A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A8B0 */ B, B, B, B, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, - /* A8C0 */ VPst, VPst, VPst, VPst, H, VMAbv, O, O, O, O, O, O, O, O, O, O, - /* A8D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* A8C0 */ VPst, VPst, VPst, VPst, H, VMAbv, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, + /* A8D0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, /* Devanagari Extended */ @@ -508,9 +511,9 @@ static const uint8_t use_table[] = { /* A930 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A940 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv, - /* A950 */ FAbv, FAbv, FPst, VPst, O, O, O, O, O, O, O, O, O, O, O, O, + /* A950 */ FAbv, FAbv, FPst, VPst, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, /* A960 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* A970 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* A970 */ O, O, O, O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, /* Javanese */ @@ -518,22 +521,22 @@ static const uint8_t use_table[] = { /* A990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A9A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, MBlw, MPst, MBlw, - /* A9C0 */ H, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* A9D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* A9C0 */ H, O, O, O, O, O, O, O, O, O, O, O, O, O, WJ, O, + /* A9D0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, O, O, /* Myanmar Extended-B */ /* A9E0 */ B, B, B, B, B, VAbv, O, B, B, B, B, B, B, B, B, B, - /* A9F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, + /* A9F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, /* Cham */ /* AA00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* AA10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* AA20 */ B, B, B, B, B, B, B, B, B, VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre, - /* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MAbv, MBlw, O, O, O, O, O, O, O, O, O, - /* AA40 */ B, B, B, FAbv, B, B, B, B, B, B, B, B, FAbv, FPst, O, O, - /* AA50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MAbv, MBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* AA40 */ B, B, B, FAbv, B, B, B, B, B, B, B, B, FAbv, FPst, WJ, WJ, + /* AA50 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, O, O, O, O, /* Myanmar Extended-A */ @@ -546,115 +549,128 @@ static const uint8_t use_table[] = { /* AA90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* AAA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* AAB0 */ VAbv, B, VAbv, VAbv, VBlw, B, B, VAbv, VAbv, B, B, B, B, B, VAbv, VMAbv, - /* AAC0 */ B, VMAbv, B, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* AAD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* AAC0 */ B, VMAbv, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* AAD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, O, /* Meetei Mayek Extensions */ /* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst, - /* AAF0 */ O, O, O, O, O, VMPst, H, O, + /* AAF0 */ O, O, O, O, O, VMPst, IS, WJ, -#define use_offset_0xabc0u 3952 +#define use_offset_0xabc0u 4040 /* Meetei Mayek */ /* ABC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* ABD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O, - /* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, WJ, WJ, + /* ABF0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0xfe00u 4016 +#define use_offset_0xfe00u 4104 /* Variation Selectors */ /* FE00 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, -#define use_offset_0x10570u 4032 +#define use_offset_0xfef8u 4120 + + + /* Arabic Presentation Forms-B */ + O, O, O, O, O, WJ, WJ, WJ, + +#define use_offset_0xfff0u 4128 + + + /* Specials */ + + /* FFF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, O, WJ, WJ, + +#define use_offset_0x10570u 4144 /* Vithkuqi */ - /* 10570 */ B, B, B, B, B, B, B, B, B, B, B, O, B, B, B, B, - /* 10580 */ B, B, B, B, B, B, B, B, B, B, B, O, B, B, B, B, - /* 10590 */ B, B, B, O, B, B, O, B, B, B, B, B, B, B, B, B, - /* 105A0 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 105B0 */ B, B, O, B, B, B, B, B, B, B, O, B, B, O, O, O, + /* 10570 */ B, B, B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, + /* 10580 */ B, B, B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, + /* 10590 */ B, B, B, WJ, B, B, WJ, B, B, B, B, B, B, B, B, B, + /* 105A0 */ B, B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 105B0 */ B, B, WJ, B, B, B, B, B, B, B, WJ, B, B, WJ, WJ, WJ, -#define use_offset_0x10a00u 4112 +#define use_offset_0x10a00u 4224 /* Kharoshthi */ - /* 10A00 */ B, VBlw, VBlw, VBlw, O, VAbv, VBlw, O, O, O, O, O, VPst, VMBlw, VMBlw, VMAbv, - /* 10A10 */ B, B, B, B, O, B, B, B, O, B, B, B, B, B, B, B, + /* 10A00 */ B, VBlw, VBlw, VBlw, WJ, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, VPst, VMBlw, VMBlw, VMAbv, + /* 10A10 */ B, B, B, B, WJ, B, B, B, WJ, B, B, B, B, B, B, B, /* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10A30 */ B, B, B, B, B, B, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H, - /* 10A40 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, + /* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMBlw, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS, + /* 10A40 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x10ac0u 4192 +#define use_offset_0x10ac0u 4304 /* Manichaean */ /* 10AC0 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B, /* 10AD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10AE0 */ B, B, B, B, B, CMBlw, CMBlw, O, O, O, O, B, B, B, B, B, + /* 10AE0 */ B, B, B, B, B, CMBlw, CMBlw, WJ, WJ, WJ, WJ, B, B, B, B, B, -#define use_offset_0x10b80u 4240 +#define use_offset_0x10b80u 4352 /* Psalter Pahlavi */ /* 10B80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10B90 */ B, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 10BA0 */ O, O, O, O, O, O, O, O, O, B, B, B, B, B, B, O, + /* 10B90 */ B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, WJ, WJ, WJ, + /* 10BA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, B, B, O, -#define use_offset_0x10d00u 4288 +#define use_offset_0x10d00u 4400 /* Hanifi Rohingya */ /* 10D00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 10D10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10D20 */ B, B, B, B, VMAbv, VMAbv, VMAbv, CMAbv, O, O, O, O, O, O, O, O, - /* 10D30 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 10D20 */ B, B, B, B, VMAbv, VMAbv, VMAbv, CMAbv, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 10D30 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x10e80u 4352 +#define use_offset_0x10e80u 4464 /* Yezidi */ /* 10E80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 10E90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10EA0 */ B, B, B, B, B, B, B, B, B, B, O, VAbv, VAbv, O, O, O, - /* 10EB0 */ B, B, O, O, O, O, O, O, + /* 10EA0 */ B, B, B, B, B, B, B, B, B, B, WJ, VAbv, VAbv, O, WJ, WJ, + /* 10EB0 */ B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x10f30u 4408 +#define use_offset_0x10f30u 4520 /* Sogdian */ /* 10F30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 10F40 */ B, B, B, B, B, B, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, - /* 10F50 */ VMBlw, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, - /* 10F60 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 10F50 */ VMBlw, B, B, B, B, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, + /* 10F60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Old Uyghur */ /* 10F70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10F80 */ B, B, CMBlw, CMBlw, CMBlw, CMBlw, O, O, O, O, O, O, O, O, O, O, - /* 10F90 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 10FA0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 10F80 */ B, B, CMBlw, CMBlw, CMBlw, CMBlw, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, + /* 10F90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 10FA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Chorasmian */ /* 10FB0 */ B, O, B, B, B, B, B, O, B, B, B, B, B, B, B, B, - /* 10FC0 */ O, B, B, B, B, O, O, O, O, B, B, B, O, O, O, O, - /* 10FD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 10FC0 */ O, B, B, B, B, O, O, O, O, B, B, B, WJ, WJ, WJ, WJ, + /* 10FD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* 10FE0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 10FF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 10FF0 */ O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Brahmi */ @@ -662,10 +678,10 @@ static const uint8_t use_table[] = { /* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, - /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O, - /* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, WJ, WJ, + /* 11050 */ WJ, WJ, N, N, N, N, N, N, N, N, N, N, N, N, N, N, /* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B, - /* 11070 */ VAbv, B, B, VAbv, VAbv, B, O, O, O, O, O, O, O, O, O, HN, + /* 11070 */ VAbv, B, B, VAbv, VAbv, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, HN, /* Kaithi */ @@ -673,9 +689,9 @@ static const uint8_t use_table[] = { /* 11090 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O, - /* 110C0 */ O, O, VBlw, O, O, O, O, O, + /* 110C0 */ O, O, VBlw, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x11100u 4816 +#define use_offset_0x11100u 4928 /* Chakma */ @@ -683,14 +699,14 @@ static const uint8_t use_table[] = { /* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv, - /* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, O, B, B, B, B, B, B, B, B, B, B, - /* 11140 */ O, O, O, O, B, VPst, VPst, B, O, O, O, O, O, O, O, O, + /* 11130 */ VBlw, VAbv, VAbv, IS, CMAbv, WJ, B, B, B, B, B, B, B, B, B, B, + /* 11140 */ O, O, O, O, B, VPst, VPst, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Mahajani */ /* 11150 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11160 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11170 */ B, B, B, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11170 */ B, B, B, CMBlw, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Sharada */ @@ -698,50 +714,50 @@ static const uint8_t use_table[] = { /* 11190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, - /* 111C0 */ H, B, R, R, O, O, O, O, GB, FMBlw, CMBlw, VAbv, VBlw, O, VPre, VMAbv, + /* 111C0 */ H, B, R, R, O, O, O, O, O, FMBlw, CMBlw, VAbv, VBlw, O, VPre, VMAbv, /* 111D0 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, /* Sinhala Archaic Numbers */ - /* 111E0 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 111F0 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, + /* 111E0 */ WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 111F0 */ B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Khojki */ /* 11200 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11210 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 11210 */ B, B, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw, - /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O, + /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, WJ, -#define use_offset_0x11280u 5136 +#define use_offset_0x11280u 5248 /* Multani */ - /* 11280 */ B, B, B, B, B, B, B, O, B, O, B, B, B, B, O, B, - /* 11290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, B, - /* 112A0 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, + /* 11280 */ B, B, B, B, B, B, B, WJ, B, WJ, B, B, B, B, WJ, B, + /* 11290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, B, + /* 112A0 */ B, B, B, B, B, B, B, B, B, O, WJ, WJ, WJ, WJ, WJ, WJ, /* Khudawadi */ /* 112B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 112C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 112D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, - /* 112E0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, CMBlw, VBlw, O, O, O, O, O, - /* 112F0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 112E0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, CMBlw, VBlw, WJ, WJ, WJ, WJ, WJ, + /* 112F0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, /* Grantha */ - /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv, O, B, B, B, B, B, B, B, B, O, O, B, - /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, - /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, - /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, HVM, O, O, - /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B, - /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, - /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, + /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv, WJ, B, B, B, B, B, B, B, B, WJ, WJ, B, + /* 11310 */ B, WJ, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 11320 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, + /* 11330 */ B, WJ, B, B, WJ, B, B, B, B, B, WJ, CMBlw, CMBlw, B, VPst, VPst, + /* 11340 */ VAbv, VPst, VPst, VPst, VPst, WJ, WJ, VPre, VPre, WJ, WJ, VPre, VPre, H, WJ, WJ, + /* 11350 */ O, WJ, WJ, WJ, WJ, WJ, WJ, VPst, WJ, WJ, WJ, WJ, WJ, O, B, B, + /* 11360 */ B, B, VPst, VPst, WJ, WJ, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, WJ, WJ, WJ, + /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, WJ, WJ, WJ, -#define use_offset_0x11400u 5384 +#define use_offset_0x11400u 5496 /* Newa */ @@ -751,9 +767,9 @@ static const uint8_t use_table[] = { /* 11420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11430 */ B, B, B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, /* 11440 */ VPst, VPst, H, VMAbv, VMAbv, VMPst, CMBlw, B, O, O, O, O, O, O, O, O, - /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, FMAbv, B, - /* 11460 */ CS, CS, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 11470 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, WJ, O, FMAbv, B, + /* 11460 */ CS, CS, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11470 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Tirhuta */ @@ -761,10 +777,10 @@ static const uint8_t use_table[] = { /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv, - /* 114C0 */ VMAbv, VMAbv, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O, - /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 114C0 */ VMAbv, VMAbv, H, CMBlw, B, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 114D0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x11580u 5608 +#define use_offset_0x11580u 5720 /* Siddham */ @@ -772,11 +788,11 @@ static const uint8_t use_table[] = { /* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst, - /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H, + /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, WJ, WJ, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H, /* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O, - /* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 115F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, WJ, WJ, + /* 115E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 115F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Modi */ @@ -784,31 +800,31 @@ static const uint8_t use_table[] = { /* 11610 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11620 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11630 */ VPst, VPst, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPst, VPst, VMAbv, VMPst, H, - /* 11640 */ VAbv, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 11650 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 11660 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 11670 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11640 */ VAbv, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11650 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11660 */ O, O, O, O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, + /* 11670 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Takri */ /* 11680 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11690 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 116A0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMPst, VAbv, VPre, VPst, - /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, B, O, O, O, O, O, O, O, - /* 116C0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 116D0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 116E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 116F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, B, O, WJ, WJ, WJ, WJ, WJ, WJ, + /* 116C0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, + /* 116D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 116E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 116F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Ahom */ /* 11700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11710 */ B, B, B, B, B, B, B, B, B, B, B, O, O, MBlw, MPre, MAbv, - /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O, + /* 11710 */ B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, MBlw, MPre, MAbv, + /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, WJ, WJ, WJ, WJ, /* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, - /* 11740 */ B, B, B, B, B, B, B, O, + /* 11740 */ B, B, B, B, B, B, B, WJ, -#define use_offset_0x11800u 6064 +#define use_offset_0x11800u 6176 /* Dogra */ @@ -816,31 +832,31 @@ static const uint8_t use_table[] = { /* 11800 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw, - /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O, + /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, WJ, WJ, WJ, WJ, -#define use_offset_0x11900u 6128 +#define use_offset_0x11900u 6240 /* Dives Akuru */ - /* 11900 */ B, B, B, B, B, B, B, O, O, B, O, O, B, B, B, B, - /* 11910 */ B, B, B, B, O, B, B, O, B, B, B, B, B, B, B, B, + /* 11900 */ B, B, B, B, B, B, B, WJ, WJ, B, WJ, WJ, B, B, B, B, + /* 11910 */ B, B, B, B, WJ, B, B, WJ, B, B, B, B, B, B, B, B, /* 11920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, O, VPre, VPre, O, O, VMAbv, VMAbv, VPst, H, R, - /* 11940 */ MPst, R, MPst, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, - /* 11950 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, WJ, VPre, VPre, WJ, WJ, VMAbv, VMAbv, VPst, IS, R, + /* 11940 */ MPst, R, MPst, CMBlw, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11950 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x119a0u 6224 +#define use_offset_0x119a0u 6336 /* Nandinagari */ - /* 119A0 */ B, B, B, B, B, B, B, B, O, O, B, B, B, B, B, B, + /* 119A0 */ B, B, B, B, B, B, B, B, WJ, WJ, B, B, B, B, B, B, /* 119B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 119C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 119D0 */ B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VAbv, VAbv, VPst, VPst, VMPst, VMPst, - /* 119E0 */ H, B, O, O, VPre, O, O, O, O, O, O, O, O, O, O, O, - /* 119F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 119D0 */ B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, WJ, WJ, VAbv, VAbv, VPst, VPst, VMPst, VMPst, + /* 119E0 */ H, B, O, O, VPre, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 119F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Zanabazar Square */ @@ -848,7 +864,7 @@ static const uint8_t use_table[] = { /* 11A10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A30 */ B, B, B, FMBlw, VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst, R, MBlw, MBlw, MBlw, MBlw, GB, - /* 11A40 */ O, O, O, O, O, GB, O, H, O, O, O, O, O, O, O, O, + /* 11A40 */ O, O, O, O, O, GB, O, IS, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Soyombo */ @@ -856,50 +872,50 @@ static const uint8_t use_table[] = { /* 11A60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A80 */ B, B, B, B, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, - /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O, + /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, IS, O, O, O, B, O, O, -#define use_offset_0x11c00u 6480 +#define use_offset_0x11c00u 6592 /* Bhaiksuki */ - /* 11C00 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, + /* 11C00 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B, /* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst, - /* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H, - /* 11C40 */ B, O, O, O, GB, GB, O, O, O, O, O, O, O, O, O, O, + /* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, WJ, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H, + /* 11C40 */ B, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, + /* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, /* Marchen */ /* 11C70 */ O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11C80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11C90 */ O, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, - /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, - /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O, + /* 11C90 */ WJ, WJ, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, WJ, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, WJ, -#define use_offset_0x11d00u 6664 +#define use_offset_0x11d00u 6776 /* Masaram Gondi */ - /* 11D00 */ B, B, B, B, B, B, B, O, B, B, O, B, B, B, B, B, + /* 11D00 */ B, B, B, B, B, B, B, WJ, B, B, WJ, B, B, B, B, B, /* 11D10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11D30 */ B, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, O, O, O, VAbv, O, VAbv, VAbv, O, VAbv, - /* 11D40 */ VMAbv, VMAbv, CMBlw, VAbv, VBlw, H, R, MBlw, O, O, O, O, O, O, O, O, - /* 11D50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 11D30 */ B, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, WJ, WJ, WJ, VAbv, WJ, VAbv, VAbv, WJ, VAbv, + /* 11D40 */ VMAbv, VMAbv, CMBlw, VAbv, VBlw, IS, R, MBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11D50 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, /* Gunjala Gondi */ - /* 11D60 */ B, B, B, B, B, B, O, B, B, O, B, B, B, B, B, B, + /* 11D60 */ B, B, B, B, B, B, WJ, B, B, WJ, B, B, B, B, B, B, /* 11D70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11D80 */ B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VPst, VPst, O, - /* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O, - /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 11D80 */ B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VPst, VPst, WJ, + /* 11D90 */ VAbv, VAbv, WJ, VPst, VPst, VMAbv, VMPst, IS, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x11ee0u 6840 +#define use_offset_0x11ee0u 6952 /* Makasar */ @@ -907,7 +923,7 @@ static const uint8_t use_table[] = { /* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O, -#define use_offset_0x13000u 6864 +#define use_offset_0x13000u 6976 /* Egyptian Hieroglyphs */ @@ -978,21 +994,21 @@ static const uint8_t use_table[] = { /* 133F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 13400 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 13410 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 13420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, + /* 13420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, /* Egyptian Hieroglyph Format Controls */ - /* 13430 */ H, H, H, H, H, H, H, B, B, O, O, O, O, O, O, O, + /* 13430 */ H, H, H, H, H, H, H, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, -#define use_offset_0x16ac0u 7952 +#define use_offset_0x16ac0u 8064 /* Tangsa */ - /* 16AC0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 16AC0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, /* 16AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 16AE0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 16AF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 16AE0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, WJ, WJ, + /* 16AF0 */ O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Pahawh Hmong */ @@ -1001,7 +1017,7 @@ static const uint8_t use_table[] = { /* 16B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 16B30 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, -#define use_offset_0x16f00u 8072 +#define use_offset_0x16f00u 8184 /* Miao */ @@ -1010,21 +1026,21 @@ static const uint8_t use_table[] = { /* 16F10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 16F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 16F30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 16F40 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, CMBlw, + /* 16F40 */ B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, CMBlw, /* 16F50 */ O, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, /* 16F60 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, /* 16F70 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, - /* 16F80 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, O, O, O, O, O, O, O, VMBlw, + /* 16F80 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, VMBlw, /* 16F90 */ VMBlw, VMBlw, VMBlw, O, O, O, O, O, -#define use_offset_0x16fe0u 8224 +#define use_offset_0x16fe0u 8336 /* Ideographic Symbols and Punctuation */ - /* 16FE0 */ O, O, O, O, B, O, O, O, + /* 16FE0 */ O, O, O, O, B, WJ, WJ, WJ, -#define use_offset_0x18b00u 8232 +#define use_offset_0x18b00u 8344 /* Khitan Small Script */ @@ -1058,9 +1074,9 @@ static const uint8_t use_table[] = { /* 18CA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 18CB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 18CC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 18CD0 */ B, B, B, B, B, B, O, O, + /* 18CD0 */ B, B, B, B, B, B, WJ, WJ, -#define use_offset_0x1bc00u 8704 +#define use_offset_0x1bc00u 8816 /* Duployan */ @@ -1071,39 +1087,46 @@ static const uint8_t use_table[] = { /* 1BC30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1BC40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1BC50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1BC60 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, - /* 1BC70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, - /* 1BC80 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, - /* 1BC90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, CMBlw, CMBlw, O, + /* 1BC60 */ B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, + /* 1BC70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, + /* 1BC80 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* 1BC90 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, O, CMBlw, CMBlw, O, + +#define use_offset_0x1d170u 8976 + -#define use_offset_0x1e100u 8864 + /* Musical Symbols */ + + /* 1D170 */ O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, O, O, O, O, O, + +#define use_offset_0x1e100u 8992 /* Nyiakeng Puachue Hmong */ /* 1E100 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1E110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1E120 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, - /* 1E130 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, O, O, - /* 1E140 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, B, B, + /* 1E120 */ B, B, B, B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, + /* 1E130 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, WJ, WJ, + /* 1E140 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, B, B, -#define use_offset_0x1e290u 8944 +#define use_offset_0x1e290u 9072 /* Toto */ /* 1E290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1E2A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, O, - /* 1E2B0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 1E2A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, WJ, + /* 1E2B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Wancho */ /* 1E2C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1E2D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1E2E0 */ B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMAbv, VMAbv, VMAbv, - /* 1E2F0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 1E2F0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, O, -#define use_offset_0x1e900u 9056 +#define use_offset_0x1e900u 9184 /* Adlam */ @@ -1112,11 +1135,33 @@ static const uint8_t use_table[] = { /* 1E910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1E920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1E930 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1E940 */ B, B, B, B, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, B, O, O, O, O, - /* 1E950 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 1E940 */ B, B, B, B, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, B, WJ, WJ, WJ, WJ, + /* 1E950 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, O, O, + +#define use_offset_0xe0000u 9280 + + + /* Tags */ -#define use_offset_0xe0100u 9152 + /* E0000 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0010 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0020 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0030 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0040 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0050 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0060 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0070 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* No_Block */ + + /* E0080 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0090 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E00F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, /* Variation Selectors Supplement */ @@ -1136,11 +1181,240 @@ static const uint8_t use_table[] = { /* E01D0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, /* E01E0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, -}; /* Table items: 9392; occupancy: 79% */ + /* No_Block */ + + /* E01F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0200 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0210 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0220 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0230 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0240 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0250 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0260 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0270 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0280 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0290 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E02F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0300 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0310 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0320 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0330 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0340 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0350 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0360 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0370 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0380 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0390 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E03F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0400 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0410 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0420 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0430 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0440 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0450 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0460 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0470 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0480 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0490 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E04F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0500 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0510 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0520 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0530 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0540 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0550 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0560 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0570 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0580 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0590 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E05F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0600 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0610 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0620 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0630 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0640 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0650 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0660 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0670 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0680 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0690 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E06F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0700 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0710 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0720 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0730 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0740 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0750 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0760 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0770 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0780 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0790 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E07F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0800 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0810 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0820 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0830 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0840 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0850 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0860 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0870 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0880 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0890 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E08F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0900 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0910 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0920 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0930 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0940 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0950 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0960 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0970 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0980 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0990 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09A0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09B0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09C0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09D0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09E0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E09F0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0A90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0AF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0B90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0BF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0C90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0CF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0D90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0DF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0E90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0EA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0EB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0EC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0ED0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0EE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0EF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F00 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F10 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F20 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F30 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F40 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F50 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F60 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F70 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F80 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0F90 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FA0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FB0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FC0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FD0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FE0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + /* E0FF0 */ WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, + +}; /* Table items: 13376; occupancy: 84% */ static inline uint8_t -hb_use_get_category (hb_codepoint_t u) +hb_use_get_category (hb_glyph_info_t info) { + hb_codepoint_t u = info.codepoint; switch (u >> 12) { case 0x0u: @@ -1164,8 +1438,7 @@ hb_use_get_category (hb_codepoint_t u) break; case 0x2u: - if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u]; - if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return use_table[u - 0x2070u + use_offset_0x2070u]; + if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2087u)) return use_table[u - 0x2008u + use_offset_0x2008u]; if (hb_in_range<hb_codepoint_t> (u, 0x20F0u, 0x20F7u)) return use_table[u - 0x20F0u + use_offset_0x20f0u]; if (hb_in_range<hb_codepoint_t> (u, 0x25C8u, 0x25CFu)) return use_table[u - 0x25C8u + use_offset_0x25c8u]; if (hb_in_range<hb_codepoint_t> (u, 0x2D30u, 0x2D7Fu)) return use_table[u - 0x2D30u + use_offset_0x2d30u]; @@ -1178,9 +1451,12 @@ hb_use_get_category (hb_codepoint_t u) case 0xFu: if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u]; + if (hb_in_range<hb_codepoint_t> (u, 0xFEF8u, 0xFEFFu)) return use_table[u - 0xFEF8u + use_offset_0xfef8u]; + if (hb_in_range<hb_codepoint_t> (u, 0xFFF0u, 0xFFFFu)) return use_table[u - 0xFFF0u + use_offset_0xfff0u]; break; case 0x10u: + if (hb_in_range<hb_codepoint_t> (u, 0xFFF0u, 0xFFFFu)) return use_table[u - 0xFFF0u + use_offset_0xfff0u]; if (hb_in_range<hb_codepoint_t> (u, 0x10570u, 0x105BFu)) return use_table[u - 0x10570u + use_offset_0x10570u]; if (hb_in_range<hb_codepoint_t> (u, 0x10A00u, 0x10A4Fu)) return use_table[u - 0x10A00u + use_offset_0x10a00u]; if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return use_table[u - 0x10AC0u + use_offset_0x10ac0u]; @@ -1222,6 +1498,10 @@ hb_use_get_category (hb_codepoint_t u) if (hb_in_range<hb_codepoint_t> (u, 0x1BC00u, 0x1BC9Fu)) return use_table[u - 0x1BC00u + use_offset_0x1bc00u]; break; + case 0x1Du: + if (hb_in_range<hb_codepoint_t> (u, 0x1D170u, 0x1D17Fu)) return use_table[u - 0x1D170u + use_offset_0x1d170u]; + break; + case 0x1Eu: if (hb_in_range<hb_codepoint_t> (u, 0x1E100u, 0x1E14Fu)) return use_table[u - 0x1E100u + use_offset_0x1e100u]; if (hb_in_range<hb_codepoint_t> (u, 0x1E290u, 0x1E2FFu)) return use_table[u - 0x1E290u + use_offset_0x1e290u]; @@ -1229,13 +1509,19 @@ hb_use_get_category (hb_codepoint_t u) break; case 0xE0u: - if (hb_in_range<hb_codepoint_t> (u, 0xE0100u, 0xE01EFu)) return use_table[u - 0xE0100u + use_offset_0xe0100u]; + if (hb_in_range<hb_codepoint_t> (u, 0xE0000u, 0xE0FFFu)) return use_table[u - 0xE0000u + use_offset_0xe0000u]; + break; + + case 0xE1u: + if (hb_in_range<hb_codepoint_t> (u, 0xE0000u, 0xE0FFFu)) return use_table[u - 0xE0000u + use_offset_0xe0000u]; break; default: break; } - return USE(O); + if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) + return WJ; + return O; } #undef B @@ -1245,7 +1531,7 @@ hb_use_get_category (hb_codepoint_t u) #undef GB #undef H #undef HN -#undef HVM +#undef IS #undef J #undef N #undef O @@ -1254,6 +1540,7 @@ hb_use_get_category (hb_codepoint_t u) #undef SE #undef SUB #undef Sk +#undef WJ #undef ZWNJ #undef CMAbv #undef CMBlw diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc index 70b637933d..1d13c8a126 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc @@ -115,25 +115,24 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->add_gsub_pause (setup_syllables_use); /* "Default glyph pre-processing group" */ - map->enable_feature (HB_TAG('l','o','c','l')); - map->enable_feature (HB_TAG('c','c','m','p')); - map->enable_feature (HB_TAG('n','u','k','t')); - map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE); + map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE); + map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE); + map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE); /* "Reordering group" */ map->add_gsub_pause (_hb_clear_substitution_flags); - map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); + map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (record_rphf_use); map->add_gsub_pause (_hb_clear_substitution_flags); - map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (record_pref_use); /* "Orthographic unit shaping group" */ for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++) - map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ); + map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (reorder_use); - map->add_gsub_pause (_hb_clear_syllables); /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++) @@ -206,7 +205,7 @@ setup_masks_use (const hb_ot_shape_plan_t *plan, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - info[i].use_category() = hb_use_get_category (info[i].codepoint); + info[i].use_category() = hb_use_get_category (info[i]); } static void @@ -257,7 +256,6 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F); switch (syllable_type) { - case use_symbol_cluster: case use_hieroglyph_cluster: case use_non_cluster: /* These don't join. Nothing to do. */ @@ -269,6 +267,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, case use_standard_cluster: case use_number_joiner_terminated_cluster: case use_numeral_cluster: + case use_symbol_cluster: case use_broken_cluster: bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL; @@ -350,7 +349,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED, static inline bool is_halant_use (const hb_glyph_info_t &info) { - return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) && + return (info.use_category() == USE(H) || info.use_category() == USE(IS)) && !_hb_glyph_info_ligated (&info); } @@ -363,6 +362,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) (FLAG (use_virama_terminated_cluster) | FLAG (use_sakot_terminated_cluster) | FLAG (use_standard_cluster) | + FLAG (use_symbol_cluster) | FLAG (use_broken_cluster) | 0)))) return; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc index 045731dfb4..d2cca105a4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc @@ -435,7 +435,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, default: break; } - buffer->swap_buffers (); + buffer->sync (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc b/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc index eb1bc79768..b2eedb027b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc @@ -446,6 +446,9 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, return; #endif + if (!buffer->message (font, "start fallback mark")) + return; + _hb_buffer_assert_gsubgpos_vars (buffer); unsigned int start = 0; @@ -457,6 +460,8 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, start = i; } position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing); + + (void) buffer->message (font, "end fallback mark"); } @@ -497,6 +502,9 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, !font->has_glyph_v_kerning_func ()) return; + if (!buffer->message (font, "start fallback kern")) + return; + bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); if (reverse) @@ -508,6 +516,8 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, if (reverse) buffer->reverse (); + + (void) buffer->message (font, "end fallback kern"); #endif } @@ -525,6 +535,15 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, for (unsigned int i = 0; i < count; i++) if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i])) { + /* If font had no ASCII space and we used the invisible glyph, give it a 1/4 EM default advance. */ + if (buffer->invisible && info[i].codepoint == buffer->invisible) + { + if (horizontal) + pos[i].x_advance = +font->x_scale / 4; + else + pos[i].y_advance = -font->y_scale / 4; + } + hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]); hb_codepoint_t glyph; typedef hb_unicode_funcs_t t; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc index 839cc9122c..aa5a8eeaa3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc @@ -193,7 +193,8 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor { hb_codepoint_t space_glyph; hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u); - if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph)) + if (space_type != hb_unicode_funcs_t::NOT_SPACE && + (c->font->get_nominal_glyph (0x0020, &space_glyph) || (space_glyph = buffer->invisible))) { _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type); next_char (buffer, space_glyph); @@ -374,7 +375,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, decompose_multi_char_cluster (&c, end, always_short_circuit); } while (buffer->idx < count && buffer->successful); - buffer->swap_buffers (); + buffer->sync (); } @@ -477,7 +478,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, if (info_cc (buffer->prev()) == 0) starter = buffer->out_len - 1; } - buffer->swap_buffers (); + buffer->sync (); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc index 4dde3520d8..99aadab3f0 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc @@ -47,6 +47,9 @@ #include "hb-aat-layout.hh" +static inline bool +_hb_codepoint_is_regional_indicator (hb_codepoint_t u) +{ return hb_in_range<hb_codepoint_t> (u, 0x1F1E6u, 0x1F1FFu); } #ifndef HB_NO_AAT_SHAPE static inline bool @@ -504,9 +507,9 @@ hb_set_unicode_props (hb_buffer_t *buffer) } /* Regional_Indicators are hairy as hell... * https://github.com/harfbuzz/harfbuzz/issues/2265 */ - else if (unlikely (i && hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F1E6u, 0x1F1FFu))) + else if (unlikely (i && _hb_codepoint_is_regional_indicator (info[i].codepoint))) { - if (hb_in_range<hb_codepoint_t> (info[i - 1].codepoint, 0x1F1E6u, 0x1F1FFu) && + if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) && !_hb_glyph_info_is_continuation (&info[i - 1])) _hb_glyph_info_set_continuation (&info[i]); } @@ -566,7 +569,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) info.mask = buffer->cur().mask; (void) buffer->output_info (info); - buffer->swap_buffers (); + buffer->sync (); } static void @@ -598,24 +601,33 @@ hb_ensure_native_direction (hb_buffer_t *buffer) * direction, so that features like ligatures will work as intended. * * https://github.com/harfbuzz/harfbuzz/issues/501 + * + * Similar thing about Regional_Indicators; They are bidi=L, but Script=Common. + * If they are present in a run of natively-RTL text, they get assigned a script + * with natively RTL direction, which would result in wrong shaping if we + * assign such native RTL direction to them then. Detect that as well. + * + * https://github.com/harfbuzz/harfbuzz/issues/3314 */ if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR)) { - bool found_number = false, found_letter = false; + bool found_number = false, found_letter = false, found_ri = false; const auto* info = buffer->info; const auto count = buffer->len; for (unsigned i = 0; i < count; i++) { auto gc = _hb_glyph_info_get_general_category (&info[i]); if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) - found_number = true; + found_number = true; else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) { - found_letter = true; - break; + found_letter = true; + break; } + else if (_hb_codepoint_is_regional_indicator (info[i].codepoint)) + found_ri = true; } - if (found_number && !found_letter) + if ((found_number || found_ri) && !found_letter) horiz_dir = HB_DIRECTION_LTR; } @@ -935,17 +947,23 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c) _hb_buffer_allocate_gsubgpos_vars (c->buffer); hb_ot_substitute_complex (c); + +#ifndef HB_NO_AAT_SHAPE + if (c->plan->apply_morx && c->plan->apply_gpos) + hb_aat_layout_remove_deleted_glyphs (c->buffer); +#endif } static inline void hb_ot_substitute_post (const hb_ot_shape_context_t *c) { - hb_ot_hide_default_ignorables (c->buffer, c->font); #ifndef HB_NO_AAT_SHAPE - if (c->plan->apply_morx) + if (c->plan->apply_morx && !c->plan->apply_gpos) hb_aat_layout_remove_deleted_glyphs (c->buffer); #endif + hb_ot_hide_default_ignorables (c->buffer, c->font); + if (c->plan->shaper->postprocess_glyphs && c->buffer->message(c->font, "start postprocess-glyphs")) { c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); @@ -1034,7 +1052,7 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c) * hanging over the next glyph after the final reordering. * * Note: If fallback positinoing happens, we don't care about - * this as it will be overriden. + * this as it will be overridden. */ bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing && HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); @@ -1120,7 +1138,7 @@ hb_propagate_flags (hb_buffer_t *buffer) /* Propagate cluster-level glyph flags to be the same on all cluster glyphs. * Simplifies using them. */ - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK)) + if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS)) return; hb_glyph_info_t *info = buffer->info; @@ -1129,11 +1147,7 @@ hb_propagate_flags (hb_buffer_t *buffer) { unsigned int mask = 0; for (unsigned int i = start; i < end; i++) - if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) - { - mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - break; - } + mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED; if (mask) for (unsigned int i = start; i < end; i++) info[i].mask |= mask; @@ -1145,18 +1159,7 @@ hb_propagate_flags (hb_buffer_t *buffer) static void hb_ot_shape_internal (hb_ot_shape_context_t *c) { - c->buffer->deallocate_var_all (); - c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) - { - c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); - } - if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) - { - c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); - } + c->buffer->enter (); /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; @@ -1188,9 +1191,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) c->buffer->props.direction = c->target_direction; - c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; - c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT; - c->buffer->deallocate_var_all (); + c->buffer->leave (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh index 2c6316df4f..b242fba2d8 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh @@ -6,1607 +6,1620 @@ * * on files with these headers: * - * <meta name="updated_at" content="2021-12-09 12:01 AM" /> - * File-Date: 2021-08-06 + * <meta name="updated_at" content="2022-01-28 10:00 PM" /> + * File-Date: 2022-03-02 */ #ifndef HB_OT_TAG_TABLE_HH #define HB_OT_TAG_TABLE_HH -static const LangTag ot_languages[] = { - {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ - {"aae", HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ - {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ - {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ - {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ - {"aba", HB_TAG_NONE }, /* Abé != Abaza */ - {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ - {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ - {"abs", HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ - {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ - {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ - {"acf", HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ -/*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ - {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ - {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ - {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ - {"acr", HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ - {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ - {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ - {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ - {"ada", HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ - {"adf", HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ - {"adp", HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ -/*{"ady", HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ - {"aeb", HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ - {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ - {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ - {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ - {"afk", HB_TAG_NONE }, /* Nanubae != Afrikaans */ - {"afs", HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ - {"agu", HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ - {"agw", HB_TAG_NONE }, /* Kahua != Agaw */ - {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ - {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ - {"aig", HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ - {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ - {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ -/*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */ - {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ - {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ - {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ - {"akb", HB_TAG('A','K','B',' ')}, /* Batak Angkola */ - {"akb", HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ - {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ - {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ -/*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ - {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ - {"amf", HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ - {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ - {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ -/*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ - {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ - {"apa", HB_TAG('A','T','H',' ')}, /* Apache [family] -> Athapaskan */ - {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ - {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ - {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ - {"apk", HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ - {"apl", HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ - {"apm", HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ - {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ - {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ - {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ - {"ari", HB_TAG_NONE }, /* Arikara != Aari */ - {"ark", HB_TAG_NONE }, /* Arikapú != Rakhine */ - {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ - {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ - {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ - {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ - {"ary", HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ - {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ - {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ -/*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ -/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [family] -> Athapaskan */ - {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ - {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ - {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ - {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ - {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ - {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ -/*{"avn", HB_TAG('A','V','N',' ')},*/ /* Avatime */ -/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */ - {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ - {"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ - {"ayh", HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ - {"ayl", HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ - {"ayn", HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ - {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ - {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ - {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ - {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ - {"azb", HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ - {"azd", HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ - {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ - {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ - {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ - {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda [family] */ - {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */ - {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ - {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ -/*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ -/*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ - {"bau", HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ - {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {"bbc", HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ - {"bbj", HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ - {"bbp", HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ - {"bbr", HB_TAG_NONE }, /* Girawa != Berber */ - {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ - {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ - {"bch", HB_TAG_NONE }, /* Bariai != Bench */ - {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ - {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ - {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ - {"bcr", HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ -/*{"bdy", HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ - {"be", HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ - {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ - {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ -/*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ - {"ber", HB_TAG('B','B','R',' ')}, /* Berber [family] */ - {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ - {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ - {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ - {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ - {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ - {"bfy", HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ - {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ -/*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ - {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ - {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ - {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ - {"bgq", HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ - {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ - {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ -/*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ - {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ -/*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ - {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ - {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ - {"bi", HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ -/*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ - {"bil", HB_TAG_NONE }, /* Bile != Bilen */ - {"bin", HB_TAG('E','D','O',' ')}, /* Edo */ - {"biu", HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ -/*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */ - {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ - {"bjo", HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ - {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ - {"bjs", HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ - {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ - {"bkf", HB_TAG_NONE }, /* Beeke != Blackfoot */ - {"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ - {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ - {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ - {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ - {"bli", HB_TAG_NONE }, /* Bolia != Baluchi */ - {"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ - {"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ - {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ - {"blt", HB_TAG_NONE }, /* Tai Dam != Balti */ - {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ - {"bmb", HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ - {"bml", HB_TAG_NONE }, /* Bomboli != Bamileke */ - {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ - {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ - {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ - {"bpd", HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ - {"bpl", HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ - {"bpq", HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ -/*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ - {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ - {"bqk", HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ - {"br", HB_TAG('B','R','E',' ')}, /* Breton */ - {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ - {"brc", HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ -/*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */ - {"bri", HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ - {"brm", HB_TAG_NONE }, /* Barambu != Burmese */ -/*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ - {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ - {"bsh", HB_TAG_NONE }, /* Kati != Bashkir */ -/*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */ - {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ - {"btd", HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ - {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ - {"bti", HB_TAG_NONE }, /* Burate != Beti */ - {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ -/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [family] */ - {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ - {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ - {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ - {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {"bts", HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ - {"btx", HB_TAG('B','T','X',' ')}, /* Batak Karo */ - {"btx", HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ - {"btz", HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ - {"btz", HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ -/*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ - {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ - {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ - {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ - {"bwe", HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ - {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ - {"bxo", HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ - {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ - {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ - {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ - {"byv", HB_TAG('B','Y','V',' ')}, /* Medumba */ - {"byv", HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ - {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ - {"bzj", HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ - {"bzk", HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ - {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ - {"caa", HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ - {"cac", HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ - {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ - {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ - {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {"cak", HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ - {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ - {"cbk", HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ - {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ - {"ccl", HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ - {"ccm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ - {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ - {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ - {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ - {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ -/*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */ - {"cek", HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ - {"cey", HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ - {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ - {"cfm", HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ -/*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */ - {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ - {"chf", HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ - {"chg", HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ - {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */ - {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ - {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ - {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ -/*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ - {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ - {"chp", HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ - {"chq", HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ -/*{"chr", HB_TAG('C','H','R',' ')},*/ /* Cherokee */ -/*{"chy", HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ - {"chz", HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ - {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ -/*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */ -/*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ - {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ - {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ - {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ - {"ckn", HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ - {"cks", HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ - {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ - {"ckz", HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ - {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ - {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ - {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ - {"clj", HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ - {"clt", HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ - {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ - {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ - {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ - {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ - {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ - {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ - {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ - {"cnr", HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ - {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ - {"cnu", HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ - {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ - {"co", HB_TAG('C','O','S',' ')}, /* Corsican */ - {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ - {"cob", HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ -/*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ - {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ - {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ - {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [family] -> Creoles */ - {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [family] -> Creoles */ - {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ -/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [family] -> Creoles */ - {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ - {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ - {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ - {"cqu", HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ - {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ - {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ - {"cri", HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ - {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ - {"crj", HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ - {"crj", HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ - {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ - {"crk", HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ - {"crk", HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ - {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ - {"crl", HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ - {"crl", HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ - {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ - {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ - {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [family] -> Creoles */ - {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ - {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ - {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ - {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ - {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ - {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ - {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ -/*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */ - {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ - {"csj", HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ - {"csl", HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ - {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ - {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ - {"csv", HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ - {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ - {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ - {"csw", HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ - {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ - {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ - {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ - {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ -/*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ - {"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ - {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ - {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ -/*{"ctt", HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ - {"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ - {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */ - {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ -/*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ - {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ - {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ - {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ - {"cwd", HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ - {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ - {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ - {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ - {"da", HB_TAG('D','A','N',' ')}, /* Danish */ -/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */ - {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ - {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ -/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */ -/*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */ - {"dcr", HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ - {"de", HB_TAG('D','E','U',' ')}, /* German */ - {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ - {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ - {"dep", HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ - {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ - {"dgo", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ - {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ - {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ -/*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */ - {"dhv", HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ - {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ - {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ - {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ - {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ - {"diq", HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ - {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ - {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ - {"djk", HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ - {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ - {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ - {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ -/*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */ - {"dnk", HB_TAG_NONE }, /* Dengka != Dinka */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ - {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ - {"dri", HB_TAG_NONE }, /* C'Lela != Dari */ - {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ - {"drw", HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ - {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ - {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ -/*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ - {"dun", HB_TAG_NONE }, /* Dusun Deyah != Dungan */ - {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ - {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ - {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ - {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */ - {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ - {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ - {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ - {"dzn", HB_TAG_NONE }, /* Dzando != Dzongkha */ - {"ecr", HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ - {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ -/*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */ - {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ - {"eky", HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ - {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ - {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ - {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ - {"emy", HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ - {"en", HB_TAG('E','N','G',' ')}, /* English */ - {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets */ - {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ - {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ - {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ - {"esi", HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ - {"esk", HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ -/*{"esu", HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ - {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ - {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ - {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"euq", HB_TAG_NONE }, /* Basque [family] != Basque */ - {"eve", HB_TAG('E','V','N',' ')}, /* Even */ - {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ - {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ - {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ - {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ - {"fab", HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ - {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ - {"fan", HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ - {"far", HB_TAG_NONE }, /* Fataleka != Persian */ - {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ - {"fat", HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ - {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ - {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ - {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ - {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ - {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ - {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ - {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ - {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ - {"fmp", HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ - {"fmp", HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ - {"fng", HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ - {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ -/*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */ - {"fos", HB_TAG_NONE }, /* Siraya != Faroese */ - {"fpe", HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ - {"fr", HB_TAG('F','R','A',' ')}, /* French */ -/*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */ -/*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */ - {"fub", HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ - {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ - {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ - {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ - {"fuf", HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ - {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ - {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ - {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ - {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ - {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {"fuv", HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ - {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ - {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ - {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ - {"gac", HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ - {"gad", HB_TAG_NONE }, /* Gaddang != Ga */ - {"gae", HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ -/*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */ - {"gal", HB_TAG_NONE }, /* Galolen != Galician */ - {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ - {"gar", HB_TAG_NONE }, /* Galeya != Garshuni */ - {"gaw", HB_TAG_NONE }, /* Nobonob != Garhwali */ - {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ - {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ - {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ - {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ - {"gcf", HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ - {"gcl", HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ - {"gcr", HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ - {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ - {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ -/*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */ - {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ - {"gha", HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ - {"ghk", HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ - {"gho", HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ - {"gib", HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ -/*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */ - {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ - {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ - {"gkp", HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ - {"gkp", HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ - {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ - {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ -/*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */ - {"gmz", HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ - {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ - {"gnb", HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ -/*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */ - {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ - {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ -/*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */ - {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ -/*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ - {"goq", HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ - {"gox", HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ - {"gpe", HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ - {"gro", HB_TAG_NONE }, /* Groma != Garo */ - {"grr", HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ - {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ - {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ - {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ - {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ - {"gua", HB_TAG_NONE }, /* Shiki != Guarani */ -/*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */ -/*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ - {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ - {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ - {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ - {"gul", HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ - {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ -/*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */ - {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ - {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ - {"gyn", HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ - {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ - {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ - {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ - {"hai", HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ - {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ - {"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ - {"har", HB_TAG('H','R','I',' ')}, /* Harari */ -/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ - {"hax", HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ -/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */ -/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ - {"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */ - {"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ - {"hdn", HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ - {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ - {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ -/*{"hei", HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ - {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ -/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ - {"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ - {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ - {"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ - {"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ - {"hmd", HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ - {"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ - {"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ - {"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ - {"hmh", HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ - {"hmi", HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ - {"hmj", HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ - {"hml", HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ - {"hmm", HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ -/*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ - {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ - {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ - {"hmr", HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ - {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ - {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ - {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ - {"hmz", HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ - {"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ -/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ - {"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ - {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ - {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ - {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ - {"ho", HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ - {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ - {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ - {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ - {"hoj", HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ - {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ - {"hra", HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ - {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ - {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ - {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ - {"ht", HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ - {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ - {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ - {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ - {"hus", HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ - {"hwc", HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ - {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ - {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ - {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ - {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ - {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ -/*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */ -/*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */ - {"iby", HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ - {"icr", HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ - {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ - {"id", HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ - {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ - {"idb", HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ - {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */ - {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ - {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ - {"ihb", HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ - {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ - {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ - {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ - {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ -/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [family] */ - {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ - {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ - {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ - {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ -/*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ - {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ - {"in", HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ - {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ - {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ - {"io", HB_TAG('I','D','O',' ')}, /* Ido */ - {"iri", HB_TAG_NONE }, /* Rigwe != Irish */ -/*{"iru", HB_TAG('I','R','U',' ')},*/ /* Irula */ - {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ - {"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */ - {"it", HB_TAG('I','T','A',' ')}, /* Italian */ - {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ - {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ - {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ - {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ - {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ - {"jac", HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ - {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ - {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ - {"jam", HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ - {"jan", HB_TAG_NONE }, /* Jandai != Japanese */ - {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ - {"jbe", HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ - {"jbn", HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ -/*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */ -/*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */ - {"jgo", HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ - {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ - {"jii", HB_TAG_NONE }, /* Jiiddu != Yiddish */ - {"jkm", HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ - {"jkp", HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ - {"jud", HB_TAG_NONE }, /* Worodougou != Ladino */ - {"jul", HB_TAG_NONE }, /* Jirel != Jula */ - {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ - {"jvd", HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ - {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ - {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ - {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ - {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */ - {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ -/*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ - {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ - {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ - {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ - {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ - {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ - {"kcn", HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ -/*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */ - {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ - {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ - {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {"kea", HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ - {"keb", HB_TAG_NONE }, /* Kélé != Kebena */ - {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ - {"kek", HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ - {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ - {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ - {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ - {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ - {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ - {"kge", HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ - {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ - {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ - {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ - {"khn", HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ - {"khs", HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ - {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ - {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ - {"khv", HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ -/*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */ - {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ - {"kis", HB_TAG_NONE }, /* Kis != Kisii */ - {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {"kiu", HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ - {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */ - {"kjb", HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ -/*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ - {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ - {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ - {"kjp", HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ - {"kjt", HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ -/*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ - {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ - {"kkn", HB_TAG_NONE }, /* Kon Keu != Kokni */ - {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ - {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */ - {"klm", HB_TAG_NONE }, /* Migum != Kalmyk */ - {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ - {"km", HB_TAG('K','H','M',' ')}, /* Khmer */ - {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ - {"kmn", HB_TAG_NONE }, /* Awtuw != Kumaoni */ - {"kmo", HB_TAG_NONE }, /* Kwoma != Komo */ - {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ - {"kms", HB_TAG_NONE }, /* Kamasau != Komso */ - {"kmv", HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ - {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ -/*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ - {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ - {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ - {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ - {"knj", HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ - {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ - {"knr", HB_TAG_NONE }, /* Kaningra != Kanuri */ - {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ - {"ko", HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ - {"kod", HB_TAG_NONE }, /* Kodi != Kodagu */ - {"koh", HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ - {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {"koi", HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ -/*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ - {"kop", HB_TAG_NONE }, /* Waube != Komi-Permyak */ -/*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */ - {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ - {"koz", HB_TAG_NONE }, /* Korak != Komi-Zyrian */ - {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {"kpl", HB_TAG_NONE }, /* Kpala != Kpelle */ - {"kpp", HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ - {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {"kpv", HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ - {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ - {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ - {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ - {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ - {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ - {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ - {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ - {"kri", HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ - {"krk", HB_TAG_NONE }, /* Kerek != Karakalpak */ -/*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */ - {"krm", HB_TAG_NONE }, /* Krim (retired code) != Karaim */ - {"krn", HB_TAG_NONE }, /* Sapo != Karen */ - {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ - {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ - {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ - {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ - {"ksi", HB_TAG_NONE }, /* Krisa != Khasi */ - {"ksm", HB_TAG_NONE }, /* Kumba != Kildin Sami */ - {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ - {"ksw", HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ - {"ksw", HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ - {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ - {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ - {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ - {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ - {"kui", HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ - {"kul", HB_TAG_NONE }, /* Kulere != Kulvi */ -/*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */ - {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ - {"kuw", HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ - {"kuy", HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ - {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ - {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ - {"kvl", HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ - {"kvq", HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ - {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ - {"kvt", HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ - {"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ - {"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ - {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ -/*{"kwk", HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ - {"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ - {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ - {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ - {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ - {"kxf", HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ - {"kxk", HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ - {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ - {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ - {"kyk", HB_TAG_NONE }, /* Kamayo != Koryak */ - {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {"kyu", HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ - {"la", HB_TAG('L','A','T',' ')}, /* Latin */ - {"lac", HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ - {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ - {"lah", HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ - {"lak", HB_TAG_NONE }, /* Laka (Nigeria) != Lak */ - {"lam", HB_TAG_NONE }, /* Lamba != Lambani */ - {"laz", HB_TAG_NONE }, /* Aribwatsa != Laz */ - {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ - {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ - {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ - {"lbl", HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ - {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ - {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ - {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ - {"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */ -/*{"lef", HB_TAG('L','E','F',' ')},*/ /* Lelemi */ -/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ - {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ - {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */ - {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ -/*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */ - {"lir", HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ -/*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */ - {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ - {"liy", HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ -/*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ - {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ -/*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */ - {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ - {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ - {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ - {"lma", HB_TAG_NONE }, /* East Limba != Low Mari */ - {"lmb", HB_TAG_NONE }, /* Merei != Limbu */ - {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ -/*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */ - {"lmw", HB_TAG_NONE }, /* Lake Miwok != Lomwe */ - {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ - {"lna", HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ - {"lnl", HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ - {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ -/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ - {"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ -/*{"lpo", HB_TAG('L','P','O',' ')},*/ /* Lipo */ -/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ - {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ - {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ - {"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ - {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ - {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ - {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ - {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ - {"lth", HB_TAG_NONE }, /* Thur != Lithuanian */ - {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ - {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ - {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ -/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ -/*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ - {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ - {"lus", HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ - {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ - {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ - {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ - {"lvi", HB_TAG_NONE }, /* Lavi != Latvian */ - {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ - {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ - {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ - {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ -/*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ -/*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */ - {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ - {"maj", HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ - {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ - {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ - {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ - {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ - {"map", HB_TAG_NONE }, /* Austronesian [family] != Mapudungun */ - {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */ - {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ - {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ - {"mbf", HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ - {"mbn", HB_TAG_NONE }, /* Macaguán != Mbundu */ -/*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ - {"mch", HB_TAG_NONE }, /* Maquiritari != Manchu */ - {"mcm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ - {"mcr", HB_TAG_NONE }, /* Menya != Moose Cree */ - {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ - {"mde", HB_TAG_NONE }, /* Maba (Chad) != Mende */ - {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ -/*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */ - {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ - {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ - {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ -/*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */ - {"mfa", HB_TAG('M','F','A',' ')}, /* Pattani Malay */ - {"mfa", HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ - {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ - {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ - {"mfe", HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ - {"mfp", HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ - {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ - {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ - {"mhc", HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ - {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ - {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ - {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ - {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {"min", HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ - {"miz", HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ - {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ - {"mkn", HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ - {"mkr", HB_TAG_NONE }, /* Malas != Makasar */ - {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ -/*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ - {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ - {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ - {"mle", HB_TAG_NONE }, /* Manambu != Male */ - {"mln", HB_TAG_NONE }, /* Malango != Malinke */ - {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ - {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ - {"mlr", HB_TAG_NONE }, /* Vame != Malayalam Reformed */ - {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ - {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ - {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ - {"mnd", HB_TAG_NONE }, /* Mondé != Mandinka */ - {"mng", HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ - {"mnh", HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ -/*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */ - {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ - {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ - {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ - {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ - {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ - {"mnw", HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ - {"mnx", HB_TAG_NONE }, /* Manikion != Manx */ - {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ - {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ -/*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ - {"mok", HB_TAG_NONE }, /* Morori != Moksha */ - {"mop", HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ - {"mor", HB_TAG_NONE }, /* Moro != Moroccan */ -/*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */ - {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ - {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ - {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ - {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ - {"mrj", HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ - {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ - {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ - {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ - {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ - {"msi", HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ - {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ - {"mth", HB_TAG_NONE }, /* Munggui != Maithili */ - {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ - {"mts", HB_TAG_NONE }, /* Yora != Maltese */ - {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ - {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ - {"mun", HB_TAG_NONE }, /* Munda [family] != Mundari */ - {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ - {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ -/*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ - {"mvb", HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ - {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ - {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ - {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ -/*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */ - {"mwq", HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ - {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ - {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ - {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ -/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [family] */ - {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ - {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ - {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ -/*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ - {"mzs", HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ - {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ - {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ - {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ -/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [family] */ - {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ -/*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ - {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */ - {"naz", HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ - {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ - {"nch", HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ - {"nci", HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ - {"ncj", HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ - {"ncl", HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ - {"ncr", HB_TAG_NONE }, /* Ncane != N-Cree */ - {"ncx", HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ - {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ - {"ndb", HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ -/*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */ - {"ndg", HB_TAG_NONE }, /* Ndengereko != Ndonga */ -/*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ - {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ - {"nef", HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ -/*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */ - {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ -/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ - {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ - {"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */ - {"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ - {"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ - {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ - {"nhe", HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ - {"nhg", HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ - {"nhi", HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ - {"nhk", HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ - {"nhm", HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ - {"nhn", HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ - {"nhp", HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ - {"nhq", HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ - {"nht", HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ - {"nhv", HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ - {"nhw", HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ - {"nhx", HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ - {"nhy", HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ - {"nhz", HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ - {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ - {"nis", HB_TAG_NONE }, /* Nimi != Nisi */ -/*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */ - {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ - {"njt", HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ - {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ - {"nko", HB_TAG_NONE }, /* Nkonya != N’Ko */ - {"nkx", HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ - {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ - {"nla", HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ - {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ - {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ - {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ - {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - {"nn", HB_TAG('N','O','R',' ')}, /* Norwegian Nynorsk -> Norwegian */ - {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ - {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ - {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ - {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ -/*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */ -/*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */ -/*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */ - {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */ - {"npl", HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ - {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */ - {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ - {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ - {"nsm", HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ - {"nsu", HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ - {"nto", HB_TAG_NONE }, /* Ntomba != Esperanto */ - {"nue", HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ - {"nuu", HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ - {"nuz", HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ - {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ - {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ - {"nwe", HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ - {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ - {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ -/*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ - {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ -/*{"nza", HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ - {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ - {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ -/*{"ojb", HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ - {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ - {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ - {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ - {"ojs", HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ - {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ - {"okd", HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ - {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ - {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ - {"okr", HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ - {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ - {"onx", HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ - {"oor", HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ - {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ - {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ - {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ - {"oro", HB_TAG_NONE }, /* Orokolo != Oromo */ - {"orr", HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ - {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ - {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ - {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ - {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ - {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ - {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ - {"paa", HB_TAG_NONE }, /* Papuan [family] != Palestinian Aramaic */ -/*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ - {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */ -/*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ - {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ - {"pap", HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ - {"pas", HB_TAG_NONE }, /* Papasena != Pashto */ -/*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */ - {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ - {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ -/*{"pcc", HB_TAG('P','C','C',' ')},*/ /* Bouyei */ -/*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */ - {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ - {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ - {"pcm", HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ -/*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ - {"pdu", HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ - {"pea", HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ - {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ - {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ - {"pey", HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ - {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ - {"pga", HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ -/*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */ - {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ - {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ - {"pih", HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ - {"pil", HB_TAG_NONE }, /* Yom != Filipino */ - {"pis", HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ - {"pkh", HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ - {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ - {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ - {"plg", HB_TAG_NONE }, /* Pilagá != Palaung */ - {"plk", HB_TAG_NONE }, /* Kohistani Shina != Polish */ - {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ - {"pln", HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ - {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ - {"pml", HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ -/*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */ - {"pmy", HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ -/*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ - {"poc", HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ - {"poh", HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ - {"poh", HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ -/*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ - {"pov", HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ - {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ - {"pre", HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ -/*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ - {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ - {"prs", HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ - {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ - {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ - {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ - {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ - {"pub", HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ - {"puz", HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ - {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ - {"pwo", HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ - {"pww", HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ - {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ - {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ - {"qub", HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ - {"quc", HB_TAG('Q','U','C',' ')}, /* K’iche’ */ - {"quc", HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ - {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ - {"qud", HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ - {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ - {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ - {"qug", HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ - {"quh", HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ - {"quh", HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ - {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ - {"qul", HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ - {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ - {"qum", HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ - {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ - {"qup", HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ - {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ - {"qur", HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ - {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ - {"qus", HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ - {"quv", HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ - {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ - {"quw", HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ - {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ - {"qux", HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ - {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ -/*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ - {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ - {"qva", HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ - {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ - {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ - {"qvh", HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ - {"qvh", HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ - {"qvi", HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ - {"qvi", HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ - {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ - {"qvj", HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ - {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ - {"qvl", HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ - {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ - {"qvm", HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ - {"qvn", HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ - {"qvn", HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ - {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ - {"qvo", HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ - {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ - {"qvp", HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ - {"qvs", HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ - {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ - {"qvw", HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ - {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ - {"qvz", HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ - {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ - {"qwa", HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ - {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ - {"qwh", HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ - {"qwh", HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ - {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ - {"qws", HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ - {"qwt", HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ - {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ - {"qxa", HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ - {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ - {"qxc", HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ - {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ - {"qxh", HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ - {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ - {"qxl", HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ - {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxn", HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ - {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxo", HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ - {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ - {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ - {"qxr", HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ - {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ - {"qxt", HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ - {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ - {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ - {"qxw", HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ - {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ -/*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ - {"ral", HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ -/*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ - {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ - {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ - {"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ -/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */ -/*{"rhg", HB_TAG('R','H','G',' ')},*/ /* Rohingya */ -/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ - {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ - {"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ -/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ - {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ -/*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */ - {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ - {"rmc", HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ - {"rmf", HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ - {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ - {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ - {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ - {"rms", HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ - {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ - {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {"rmy", HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ - {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ - {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ - {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ - {"rop", HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ - {"rtc", HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ -/*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */ - {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ - {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ -/*{"rup", HB_TAG('R','U','P',' ')},*/ /* Aromanian */ - {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ - {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ - {"sad", HB_TAG_NONE }, /* Sandawe != Sadri */ - {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ - {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ -/*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */ -/*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */ - {"say", HB_TAG_NONE }, /* Saya != Sayisi */ - {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ - {"scf", HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ - {"sch", HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ - {"sci", HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ - {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ -/*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */ -/*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */ - {"scs", HB_TAG('S','C','S',' ')}, /* North Slavey */ - {"scs", HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ - {"scs", HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ - {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ - {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ - {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ - {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ - {"sds", HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ - {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ - {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ - {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ -/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */ - {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ - {"sfm", HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ - {"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ - {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ -/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ - {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ - {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */ -/*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ - {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ - {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ -/*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */ - {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ - {"shy", HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ - {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ - {"sib", HB_TAG_NONE }, /* Sebop != Sibe */ -/*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */ - {"sig", HB_TAG_NONE }, /* Paasaal != Silte Gurage */ - {"siz", HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ - {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ - {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ - {"sjs", HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ - {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ - {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ - {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */ - {"sks", HB_TAG_NONE }, /* Maia != Skolt Sami */ - {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ - {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */ - {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sla", HB_TAG_NONE }, /* Slavic [family] != Slavey */ - {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ - {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ - {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {"sml", HB_TAG_NONE }, /* Central Sama != Somali */ - {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ - {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ - {"smt", HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ - {"sn", HB_TAG('S','N','A','0')}, /* Shona */ - {"snh", HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ -/*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */ - {"so", HB_TAG('S','M','L',' ')}, /* Somali */ - {"sog", HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ -/*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */ - {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ - {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ - {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ - {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ - {"srb", HB_TAG_NONE }, /* Sora != Serbian */ - {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ - {"srk", HB_TAG_NONE }, /* Serudung Murut != Saraiki */ - {"srm", HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ - {"srn", HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ - {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ -/*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */ - {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ - {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ - {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ - {"ssl", HB_TAG_NONE }, /* Western Sisaala != South Slavey */ - {"ssm", HB_TAG_NONE }, /* Semnam != Southern Sami */ - {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho */ - {"sta", HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ -/*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ - {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ - {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ -/*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */ - {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ - {"sur", HB_TAG_NONE }, /* Mwaghavul != Suri */ - {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ -/*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */ - {"svc", HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ - {"sve", HB_TAG_NONE }, /* Serili != Swedish */ - {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ - {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ - {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ - {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */ - {"swk", HB_TAG_NONE }, /* Malawi Sena != Swahili */ - {"swn", HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ - {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ -/*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ - {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ -/*{"syl", HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ -/*{"syr", HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ -/*{"szl", HB_TAG('S','Z','L',' ')},*/ /* Silesian */ - {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ - {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ -/*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ - {"taj", HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ - {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ - {"taq", HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ - {"tas", HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ - {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ - {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ - {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ - {"tch", HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ - {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ - {"tcs", HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ - {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ - {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ -/*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ - {"tdx", HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ - {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ - {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ - {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ -/*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */ - {"tez", HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ - {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ - {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ - {"tgh", HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ - {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ - {"tgn", HB_TAG_NONE }, /* Tandaganon != Tongan */ - {"tgr", HB_TAG_NONE }, /* Tareng != Tigre */ - {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ - {"tgy", HB_TAG_NONE }, /* Togoyo != Tigrinya */ - {"th", HB_TAG('T','H','A',' ')}, /* Thai */ - {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ - {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ - {"thv", HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ - {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ - {"thz", HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ - {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ - {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ - {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ -/*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ -/*{"tjl", HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ - {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ - {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ - {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ - {"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */ - {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ -/*{"tli", HB_TAG('T','L','I',' ')},*/ /* Tlingit */ - {"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ - {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ - {"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ - {"tmn", HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ - {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ - {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"tna", HB_TAG_NONE }, /* Tacana != Tswana */ - {"tne", HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ - {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ - {"tnf", HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ - {"tng", HB_TAG_NONE }, /* Tobanga != Tonga */ - {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ - {"tod", HB_TAG('T','O','D','0')}, /* Toma */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ - {"toj", HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ - {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ - {"tor", HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ - {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ - {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ - {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ - {"trk", HB_TAG_NONE }, /* Turkic [family] != Turkish */ - {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ - {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ - {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ - {"tsg", HB_TAG_NONE }, /* Tausug != Tsonga */ -/*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */ - {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ - {"ttc", HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ - {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ - {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ - {"ttq", HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ - {"tua", HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ - {"tul", HB_TAG_NONE }, /* Tula != Tumbuka */ -/*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ - {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ - {"tuv", HB_TAG_NONE }, /* Turkana != Tuvin */ - {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ -/*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ - {"tvy", HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ - {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ - {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ - {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ - {"txy", HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ - {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ - {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ -/*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tày */ - {"tzh", HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ - {"tzj", HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ - {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ - {"tzm", HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ - {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {"tzo", HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ - {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ -/*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */ - {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */ - {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ - {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */ - {"uln", HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ -/*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */ - {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ - {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ - {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ - {"usp", HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ - {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ - {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ - {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ - {"vap", HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ - {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ -/*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */ - {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ - {"vic", HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ - {"vit", HB_TAG_NONE }, /* Viti != Vietnamese */ - {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ - {"vkp", HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ - {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ - {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ - {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ -/*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */ - {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ - {"wag", HB_TAG_NONE }, /* Wa'ema != Wagdi */ -/*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ - {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ - {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ - {"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ -/*{"wci", HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ - {"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ - {"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ - {"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ - {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ - {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ - {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ - {"wni", HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ - {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ - {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ - {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ -/*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */ - {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ - {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ - {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ - {"xbd", HB_TAG_NONE }, /* Bindal != Lü */ - {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ -/*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ -/*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */ - {"xmg", HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ - {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ - {"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ - {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ - {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ - {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ - {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ - {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ -/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */ - {"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ - {"xpe", HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ - {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ - {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ - {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ - {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ -/*{"xub", HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ -/*{"xuj", HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ - {"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ - {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ - {"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ - {"yak", HB_TAG_NONE }, /* Yakama != Sakha */ -/*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */ -/*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */ - {"yba", HB_TAG_NONE }, /* Yala != Yoruba */ - {"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ - {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ - {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ -/*{"ygp", HB_TAG('Y','G','P',' ')},*/ /* Gepo */ - {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ - {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ - {"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ -/*{"yna", HB_TAG('Y','N','A',' ')},*/ /* Aluo */ - {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ - {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ - {"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ - {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ -/*{"ywq", HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ - {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ - {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ - {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ -/*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ - {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ - {"zen", HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ - {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ - {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ - {"zgh", HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ - {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ - {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ - {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ - {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ - {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ - {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ - {"zlm", HB_TAG('M','L','Y',' ')}, /* Malay */ - {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ - {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ - {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ - {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ - {"znd", HB_TAG_NONE }, /* Zande [family] != Zande */ - {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ - {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ - {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ - {"zsm", HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ - {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ - {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ - {"zyb", HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ - {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ - {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ - {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ - {"zyp", HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ -/*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ - {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ +static const LangTag ot_languages2[] = { + {HB_TAG('a','a',' ',' '), HB_TAG('A','F','R',' ')}, /* Afar */ + {HB_TAG('a','b',' ',' '), HB_TAG('A','B','K',' ')}, /* Abkhazian */ + {HB_TAG('a','f',' ',' '), HB_TAG('A','F','K',' ')}, /* Afrikaans */ + {HB_TAG('a','k',' ',' '), HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ + {HB_TAG('a','m',' ',' '), HB_TAG('A','M','H',' ')}, /* Amharic */ + {HB_TAG('a','n',' ',' '), HB_TAG('A','R','G',' ')}, /* Aragonese */ + {HB_TAG('a','r',' ',' '), HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ + {HB_TAG('a','s',' ',' '), HB_TAG('A','S','M',' ')}, /* Assamese */ + {HB_TAG('a','v',' ',' '), HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ + {HB_TAG('a','y',' ',' '), HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ + {HB_TAG('a','z',' ',' '), HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ + {HB_TAG('b','a',' ',' '), HB_TAG('B','S','H',' ')}, /* Bashkir */ + {HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ + {HB_TAG('b','g',' ',' '), HB_TAG('B','G','R',' ')}, /* Bulgarian */ + {HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */ + {HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ + {HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ + {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */ + {HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */ + {HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */ + {HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */ + {HB_TAG('c','a',' ',' '), HB_TAG('C','A','T',' ')}, /* Catalan */ + {HB_TAG('c','e',' ',' '), HB_TAG('C','H','E',' ')}, /* Chechen */ + {HB_TAG('c','h',' ',' '), HB_TAG('C','H','A',' ')}, /* Chamorro */ + {HB_TAG('c','o',' ',' '), HB_TAG('C','O','S',' ')}, /* Corsican */ + {HB_TAG('c','r',' ',' '), HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ + {HB_TAG('c','s',' ',' '), HB_TAG('C','S','Y',' ')}, /* Czech */ + {HB_TAG('c','u',' ',' '), HB_TAG('C','S','L',' ')}, /* Church Slavonic */ + {HB_TAG('c','v',' ',' '), HB_TAG('C','H','U',' ')}, /* Chuvash */ + {HB_TAG('c','y',' ',' '), HB_TAG('W','E','L',' ')}, /* Welsh */ + {HB_TAG('d','a',' ',' '), HB_TAG('D','A','N',' ')}, /* Danish */ + {HB_TAG('d','e',' ',' '), HB_TAG('D','E','U',' ')}, /* German */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','z',' ',' '), HB_TAG('D','Z','N',' ')}, /* Dzongkha */ + {HB_TAG('e','e',' ',' '), HB_TAG('E','W','E',' ')}, /* Ewe */ + {HB_TAG('e','l',' ',' '), HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ + {HB_TAG('e','n',' ',' '), HB_TAG('E','N','G',' ')}, /* English */ + {HB_TAG('e','o',' ',' '), HB_TAG('N','T','O',' ')}, /* Esperanto */ + {HB_TAG('e','s',' ',' '), HB_TAG('E','S','P',' ')}, /* Spanish */ + {HB_TAG('e','t',' ',' '), HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ + {HB_TAG('e','u',' ',' '), HB_TAG('E','U','Q',' ')}, /* Basque */ + {HB_TAG('f','a',' ',' '), HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ + {HB_TAG('f','f',' ',' '), HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ + {HB_TAG('f','i',' ',' '), HB_TAG('F','I','N',' ')}, /* Finnish */ + {HB_TAG('f','j',' ',' '), HB_TAG('F','J','I',' ')}, /* Fijian */ + {HB_TAG('f','o',' ',' '), HB_TAG('F','O','S',' ')}, /* Faroese */ + {HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */ + {HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ + {HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */ + {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ + {HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */ + {HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ + {HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */ + {HB_TAG('g','v',' ',' '), HB_TAG('M','N','X',' ')}, /* Manx */ + {HB_TAG('h','a',' ',' '), HB_TAG('H','A','U',' ')}, /* Hausa */ + {HB_TAG('h','e',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew */ + {HB_TAG('h','i',' ',' '), HB_TAG('H','I','N',' ')}, /* Hindi */ + {HB_TAG('h','o',' ',' '), HB_TAG('H','M','O',' ')}, /* Hiri Motu */ + {HB_TAG('h','o',' ',' '), HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ + {HB_TAG('h','r',' ',' '), HB_TAG('H','R','V',' ')}, /* Croatian */ + {HB_TAG('h','t',' ',' '), HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ + {HB_TAG('h','t',' ',' '), HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ + {HB_TAG('h','u',' ',' '), HB_TAG('H','U','N',' ')}, /* Hungarian */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E',' ')}, /* Armenian */ + {HB_TAG('h','z',' ',' '), HB_TAG('H','E','R',' ')}, /* Herero */ + {HB_TAG('i','a',' ',' '), HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ + {HB_TAG('i','d',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian */ + {HB_TAG('i','d',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ + {HB_TAG('i','e',' ',' '), HB_TAG('I','L','E',' ')}, /* Interlingue */ + {HB_TAG('i','g',' ',' '), HB_TAG('I','B','O',' ')}, /* Igbo */ + {HB_TAG('i','i',' ',' '), HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ + {HB_TAG('i','k',' ',' '), HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ + {HB_TAG('i','n',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ + {HB_TAG('i','n',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ + {HB_TAG('i','o',' ',' '), HB_TAG('I','D','O',' ')}, /* Ido */ + {HB_TAG('i','s',' ',' '), HB_TAG('I','S','L',' ')}, /* Icelandic */ + {HB_TAG('i','t',' ',' '), HB_TAG('I','T','A',' ')}, /* Italian */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ + {HB_TAG('i','w',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ + {HB_TAG('j','a',' ',' '), HB_TAG('J','A','N',' ')}, /* Japanese */ + {HB_TAG('j','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ + {HB_TAG('j','v',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese */ + {HB_TAG('j','w',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ + {HB_TAG('k','a',' ',' '), HB_TAG('K','A','T',' ')}, /* Georgian */ + {HB_TAG('k','g',' ',' '), HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ + {HB_TAG('k','i',' ',' '), HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ + {HB_TAG('k','j',' ',' '), HB_TAG('K','U','A',' ')}, /* Kuanyama */ + {HB_TAG('k','k',' ',' '), HB_TAG('K','A','Z',' ')}, /* Kazakh */ + {HB_TAG('k','l',' ',' '), HB_TAG('G','R','N',' ')}, /* Greenlandic */ + {HB_TAG('k','m',' ',' '), HB_TAG('K','H','M',' ')}, /* Khmer */ + {HB_TAG('k','n',' ',' '), HB_TAG('K','A','N',' ')}, /* Kannada */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','R',' ')}, /* Korean */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ + {HB_TAG('k','r',' ',' '), HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ + {HB_TAG('k','s',' ',' '), HB_TAG('K','S','H',' ')}, /* Kashmiri */ + {HB_TAG('k','u',' ',' '), HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ + {HB_TAG('k','v',' ',' '), HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ + {HB_TAG('k','w',' ',' '), HB_TAG('C','O','R',' ')}, /* Cornish */ + {HB_TAG('k','y',' ',' '), HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ + {HB_TAG('l','a',' ',' '), HB_TAG('L','A','T',' ')}, /* Latin */ + {HB_TAG('l','b',' ',' '), HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ + {HB_TAG('l','g',' ',' '), HB_TAG('L','U','G',' ')}, /* Ganda */ + {HB_TAG('l','i',' ',' '), HB_TAG('L','I','M',' ')}, /* Limburgish */ + {HB_TAG('l','n',' ',' '), HB_TAG('L','I','N',' ')}, /* Lingala */ + {HB_TAG('l','o',' ',' '), HB_TAG('L','A','O',' ')}, /* Lao */ + {HB_TAG('l','t',' ',' '), HB_TAG('L','T','H',' ')}, /* Lithuanian */ + {HB_TAG('l','u',' ',' '), HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ + {HB_TAG('l','v',' ',' '), HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ + {HB_TAG('m','g',' ',' '), HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ + {HB_TAG('m','h',' ',' '), HB_TAG('M','A','H',' ')}, /* Marshallese */ + {HB_TAG('m','i',' ',' '), HB_TAG('M','R','I',' ')}, /* Maori */ + {HB_TAG('m','k',' ',' '), HB_TAG('M','K','D',' ')}, /* Macedonian */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ + {HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ + {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ + {HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ + {HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */ + {HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ + {HB_TAG('m','t',' ',' '), HB_TAG('M','T','S',' ')}, /* Maltese */ + {HB_TAG('m','y',' ',' '), HB_TAG('B','R','M',' ')}, /* Burmese */ + {HB_TAG('n','a',' ',' '), HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ + {HB_TAG('n','b',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ + {HB_TAG('n','d',' ',' '), HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ + {HB_TAG('n','e',' ',' '), HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ + {HB_TAG('n','g',' ',' '), HB_TAG('N','D','G',' ')}, /* Ndonga */ + {HB_TAG('n','l',' ',' '), HB_TAG('N','L','D',' ')}, /* Dutch */ + {HB_TAG('n','n',' ',' '), HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {HB_TAG('n','o',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ + {HB_TAG('n','r',' ',' '), HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ + {HB_TAG('n','v',' ',' '), HB_TAG('N','A','V',' ')}, /* Navajo */ + {HB_TAG('n','v',' ',' '), HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ + {HB_TAG('n','y',' ',' '), HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ + {HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ + {HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ + {HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ + {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ + {HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */ + {HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */ + {HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */ + {HB_TAG('p','l',' ',' '), HB_TAG('P','L','K',' ')}, /* Polish */ + {HB_TAG('p','s',' ',' '), HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ + {HB_TAG('p','t',' ',' '), HB_TAG('P','T','G',' ')}, /* Portuguese */ + {HB_TAG('q','u',' ',' '), HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ + {HB_TAG('r','m',' ',' '), HB_TAG('R','M','S',' ')}, /* Romansh */ + {HB_TAG('r','n',' ',' '), HB_TAG('R','U','N',' ')}, /* Rundi */ + {HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */ + {HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */ + {HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ + {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */ + {HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ + {HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */ + {HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */ + {HB_TAG('s','g',' ',' '), HB_TAG('S','G','O',' ')}, /* Sango */ + {HB_TAG('s','h',' ',' '), HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ + {HB_TAG('s','h',' ',' '), HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ + {HB_TAG('s','h',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ + {HB_TAG('s','i',' ',' '), HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ + {HB_TAG('s','k',' ',' '), HB_TAG('S','K','Y',' ')}, /* Slovak */ + {HB_TAG('s','l',' ',' '), HB_TAG('S','L','V',' ')}, /* Slovenian */ + {HB_TAG('s','m',' ',' '), HB_TAG('S','M','O',' ')}, /* Samoan */ + {HB_TAG('s','n',' ',' '), HB_TAG('S','N','A','0')}, /* Shona */ + {HB_TAG('s','o',' ',' '), HB_TAG('S','M','L',' ')}, /* Somali */ + {HB_TAG('s','q',' ',' '), HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ + {HB_TAG('s','r',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbian */ + {HB_TAG('s','s',' ',' '), HB_TAG('S','W','Z',' ')}, /* Swati */ + {HB_TAG('s','t',' ',' '), HB_TAG('S','O','T',' ')}, /* Southern Sotho */ + {HB_TAG('s','u',' ',' '), HB_TAG('S','U','N',' ')}, /* Sundanese */ + {HB_TAG('s','v',' ',' '), HB_TAG('S','V','E',' ')}, /* Swedish */ + {HB_TAG('s','w',' ',' '), HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ + {HB_TAG('t','a',' ',' '), HB_TAG('T','A','M',' ')}, /* Tamil */ + {HB_TAG('t','e',' ',' '), HB_TAG('T','E','L',' ')}, /* Telugu */ + {HB_TAG('t','g',' ',' '), HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ + {HB_TAG('t','h',' ',' '), HB_TAG('T','H','A',' ')}, /* Thai */ + {HB_TAG('t','i',' ',' '), HB_TAG('T','G','Y',' ')}, /* Tigrinya */ + {HB_TAG('t','k',' ',' '), HB_TAG('T','K','M',' ')}, /* Turkmen */ + {HB_TAG('t','l',' ',' '), HB_TAG('T','G','L',' ')}, /* Tagalog */ + {HB_TAG('t','n',' ',' '), HB_TAG('T','N','A',' ')}, /* Tswana */ + {HB_TAG('t','o',' ',' '), HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ + {HB_TAG('t','r',' ',' '), HB_TAG('T','R','K',' ')}, /* Turkish */ + {HB_TAG('t','s',' ',' '), HB_TAG('T','S','G',' ')}, /* Tsonga */ + {HB_TAG('t','t',' ',' '), HB_TAG('T','A','T',' ')}, /* Tatar */ + {HB_TAG('t','w',' ',' '), HB_TAG('T','W','I',' ')}, /* Twi */ + {HB_TAG('t','w',' ',' '), HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ + {HB_TAG('t','y',' ',' '), HB_TAG('T','H','T',' ')}, /* Tahitian */ + {HB_TAG('u','g',' ',' '), HB_TAG('U','Y','G',' ')}, /* Uyghur */ + {HB_TAG('u','k',' ',' '), HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {HB_TAG('u','r',' ',' '), HB_TAG('U','R','D',' ')}, /* Urdu */ + {HB_TAG('u','z',' ',' '), HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ + {HB_TAG('v','e',' ',' '), HB_TAG('V','E','N',' ')}, /* Venda */ + {HB_TAG('v','i',' ',' '), HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {HB_TAG('v','o',' ',' '), HB_TAG('V','O','L',' ')}, /* Volapük */ + {HB_TAG('w','a',' ',' '), HB_TAG('W','L','N',' ')}, /* Walloon */ + {HB_TAG('w','o',' ',' '), HB_TAG('W','L','F',' ')}, /* Wolof */ + {HB_TAG('x','h',' ',' '), HB_TAG('X','H','S',' ')}, /* Xhosa */ + {HB_TAG('y','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ + {HB_TAG('y','o',' ',' '), HB_TAG('Y','B','A',' ')}, /* Yoruba */ + {HB_TAG('z','a',' ',' '), HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ + {HB_TAG('z','h',' ',' '), HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ + {HB_TAG('z','u',' ',' '), HB_TAG('Z','U','L',' ')}, /* Zulu */ +}; + +static const LangTag ot_languages3[] = { + {HB_TAG('a','a','e',' '), HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ + {HB_TAG('a','a','o',' '), HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ + {HB_TAG('a','a','t',' '), HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ + {HB_TAG('a','b','a',' '), HB_TAG_NONE }, /* Abé != Abaza */ + {HB_TAG('a','b','h',' '), HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ + {HB_TAG('a','b','q',' '), HB_TAG('A','B','A',' ')}, /* Abaza */ + {HB_TAG('a','b','s',' '), HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ + {HB_TAG('a','b','v',' '), HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ + {HB_TAG('a','c','f',' '), HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ + {HB_TAG('a','c','f',' '), HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ +/*{HB_TAG('a','c','h',' '), HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ + {HB_TAG('a','c','m',' '), HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','c','q',' '), HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ + {HB_TAG('a','c','r',' '), HB_TAG('A','C','R',' ')}, /* Achi */ + {HB_TAG('a','c','r',' '), HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ + {HB_TAG('a','c','w',' '), HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ + {HB_TAG('a','c','x',' '), HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ + {HB_TAG('a','c','y',' '), HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ + {HB_TAG('a','d','a',' '), HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ + {HB_TAG('a','d','f',' '), HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ + {HB_TAG('a','d','p',' '), HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ +/*{HB_TAG('a','d','y',' '), HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ + {HB_TAG('a','e','b',' '), HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ + {HB_TAG('a','e','c',' '), HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ + {HB_TAG('a','f','b',' '), HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ + {HB_TAG('a','f','k',' '), HB_TAG_NONE }, /* Nanubae != Afrikaans */ + {HB_TAG('a','f','s',' '), HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ + {HB_TAG('a','g','u',' '), HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ + {HB_TAG('a','g','w',' '), HB_TAG_NONE }, /* Kahua != Agaw */ + {HB_TAG('a','h','g',' '), HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ + {HB_TAG('a','h','t',' '), HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ + {HB_TAG('a','i','g',' '), HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ + {HB_TAG('a','i','i',' '), HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + {HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */ + {HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */ + {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ + {HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ + {HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */ + {HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ + {HB_TAG('a','l','n',' '), HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ + {HB_TAG('a','l','s',' '), HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ +/*{HB_TAG('a','l','t',' '), HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ + {HB_TAG('a','m','f',' '), HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ + {HB_TAG('a','m','w',' '), HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ + {HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ + {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ + {HB_TAG('a','p','d',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ + {HB_TAG('a','p','j',' '), HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ + {HB_TAG('a','p','k',' '), HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ + {HB_TAG('a','p','l',' '), HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ + {HB_TAG('a','p','m',' '), HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {HB_TAG('a','p','w',' '), HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ + {HB_TAG('a','r','b',' '), HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ + {HB_TAG('a','r','i',' '), HB_TAG_NONE }, /* Arikara != Aari */ + {HB_TAG('a','r','k',' '), HB_TAG_NONE }, /* Arikapú != Rakhine */ + {HB_TAG('a','r','n',' '), HB_TAG('M','A','P',' ')}, /* Mapudungun */ + {HB_TAG('a','r','q',' '), HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ + {HB_TAG('a','r','s',' '), HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ + {HB_TAG('a','r','y',' '), HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ + {HB_TAG('a','r','y',' '), HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ + {HB_TAG('a','r','z',' '), HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ +/*{HB_TAG('a','s','t',' '), HB_TAG('A','S','T',' ')},*/ /* Asturian */ +/*{HB_TAG('a','t','h',' '), HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ + {HB_TAG('a','t','j',' '), HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ + {HB_TAG('a','t','v',' '), HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ + {HB_TAG('a','u','j',' '), HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ + {HB_TAG('a','u','z',' '), HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ + {HB_TAG('a','v','l',' '), HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ +/*{HB_TAG('a','v','n',' '), HB_TAG('A','V','N',' ')},*/ /* Avatime */ +/*{HB_TAG('a','w','a',' '), HB_TAG('A','W','A',' ')},*/ /* Awadhi */ + {HB_TAG('a','y','c',' '), HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ + {HB_TAG('a','y','h',' '), HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ + {HB_TAG('a','y','l',' '), HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ + {HB_TAG('a','y','n',' '), HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ + {HB_TAG('a','y','p',' '), HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','y','r',' '), HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','d',' '), HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','j',' '), HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','n',' '), HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','z',' '), HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ + {HB_TAG('b','a','d',' '), HB_TAG('B','A','D','0')}, /* Banda [collection] */ + {HB_TAG('b','a','g',' '), HB_TAG_NONE }, /* Tuki != Baghelkhandi */ + {HB_TAG('b','a','h',' '), HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ + {HB_TAG('b','a','i',' '), HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ + {HB_TAG('b','a','l',' '), HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ +/*{HB_TAG('b','a','n',' '), HB_TAG('B','A','N',' ')},*/ /* Balinese */ +/*{HB_TAG('b','a','r',' '), HB_TAG('B','A','R',' ')},*/ /* Bavarian */ + {HB_TAG('b','a','u',' '), HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ + {HB_TAG('b','b','c',' '), HB_TAG('B','B','C',' ')}, /* Batak Toba */ + {HB_TAG('b','b','c',' '), HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ + {HB_TAG('b','b','j',' '), HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ + {HB_TAG('b','b','p',' '), HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ + {HB_TAG('b','b','r',' '), HB_TAG_NONE }, /* Girawa != Berber */ + {HB_TAG('b','b','z',' '), HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ + {HB_TAG('b','c','c',' '), HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ + {HB_TAG('b','c','h',' '), HB_TAG_NONE }, /* Bariai != Bench */ + {HB_TAG('b','c','i',' '), HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ + {HB_TAG('b','c','l',' '), HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ + {HB_TAG('b','c','q',' '), HB_TAG('B','C','H',' ')}, /* Bench */ + {HB_TAG('b','c','r',' '), HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ +/*{HB_TAG('b','d','y',' '), HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ + {HB_TAG('b','e','a',' '), HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ + {HB_TAG('b','e','b',' '), HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ +/*{HB_TAG('b','e','m',' '), HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ + {HB_TAG('b','e','r',' '), HB_TAG('B','B','R',' ')}, /* Berber [collection] */ + {HB_TAG('b','e','w',' '), HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ + {HB_TAG('b','f','l',' '), HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ + {HB_TAG('b','f','q',' '), HB_TAG('B','A','D',' ')}, /* Badaga */ + {HB_TAG('b','f','t',' '), HB_TAG('B','L','T',' ')}, /* Balti */ + {HB_TAG('b','f','u',' '), HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ + {HB_TAG('b','f','y',' '), HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ +/*{HB_TAG('b','g','c',' '), HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ + {HB_TAG('b','g','n',' '), HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ + {HB_TAG('b','g','p',' '), HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ + {HB_TAG('b','g','q',' '), HB_TAG('B','G','Q',' ')}, /* Bagri */ + {HB_TAG('b','g','q',' '), HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ + {HB_TAG('b','g','r',' '), HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ + {HB_TAG('b','h','b',' '), HB_TAG('B','H','I',' ')}, /* Bhili */ +/*{HB_TAG('b','h','i',' '), HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ + {HB_TAG('b','h','k',' '), HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ +/*{HB_TAG('b','h','o',' '), HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ + {HB_TAG('b','h','r',' '), HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ +/*{HB_TAG('b','i','k',' '), HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ + {HB_TAG('b','i','l',' '), HB_TAG_NONE }, /* Bile != Bilen */ + {HB_TAG('b','i','n',' '), HB_TAG('E','D','O',' ')}, /* Edo */ + {HB_TAG('b','i','u',' '), HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ +/*{HB_TAG('b','j','j',' '), HB_TAG('B','J','J',' ')},*/ /* Kanauji */ + {HB_TAG('b','j','n',' '), HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ + {HB_TAG('b','j','o',' '), HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ + {HB_TAG('b','j','q',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {HB_TAG('b','j','s',' '), HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ + {HB_TAG('b','j','t',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ + {HB_TAG('b','k','f',' '), HB_TAG_NONE }, /* Beeke != Blackfoot */ + {HB_TAG('b','k','o',' '), HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ + {HB_TAG('b','l','a',' '), HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ + {HB_TAG('b','l','e',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ + {HB_TAG('b','l','g',' '), HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ + {HB_TAG('b','l','i',' '), HB_TAG_NONE }, /* Bolia != Baluchi */ + {HB_TAG('b','l','k',' '), HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ + {HB_TAG('b','l','k',' '), HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ + {HB_TAG('b','l','n',' '), HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ + {HB_TAG('b','l','t',' '), HB_TAG_NONE }, /* Tai Dam != Balti */ + {HB_TAG('b','m','b',' '), HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ + {HB_TAG('b','m','l',' '), HB_TAG_NONE }, /* Bomboli != Bamileke */ + {HB_TAG('b','m','m',' '), HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','p','d',' '), HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ + {HB_TAG('b','p','l',' '), HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ + {HB_TAG('b','p','q',' '), HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ +/*{HB_TAG('b','p','y',' '), HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ + {HB_TAG('b','q','i',' '), HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ + {HB_TAG('b','q','k',' '), HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ + {HB_TAG('b','r','a',' '), HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ + {HB_TAG('b','r','c',' '), HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ +/*{HB_TAG('b','r','h',' '), HB_TAG('B','R','H',' ')},*/ /* Brahui */ + {HB_TAG('b','r','i',' '), HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ + {HB_TAG('b','r','m',' '), HB_TAG_NONE }, /* Barambu != Burmese */ +/*{HB_TAG('b','r','x',' '), HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ + {HB_TAG('b','s','h',' '), HB_TAG_NONE }, /* Kati != Bashkir */ +/*{HB_TAG('b','s','k',' '), HB_TAG('B','S','K',' ')},*/ /* Burushaski */ + {HB_TAG('b','t','b',' '), HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ + {HB_TAG('b','t','i',' '), HB_TAG_NONE }, /* Burate != Beti */ + {HB_TAG('b','t','j',' '), HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ +/*{HB_TAG('b','t','k',' '), HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ + {HB_TAG('b','t','o',' '), HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','X',' ')}, /* Batak Karo */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ +/*{HB_TAG('b','u','g',' '), HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ + {HB_TAG('b','u','m',' '), HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ + {HB_TAG('b','v','e',' '), HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ + {HB_TAG('b','v','u',' '), HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ + {HB_TAG('b','w','e',' '), HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ + {HB_TAG('b','x','k',' '), HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ + {HB_TAG('b','x','o',' '), HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ + {HB_TAG('b','x','p',' '), HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ + {HB_TAG('b','x','r',' '), HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ + {HB_TAG('b','y','n',' '), HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ + {HB_TAG('b','y','v',' '), HB_TAG('B','Y','V',' ')}, /* Medumba */ + {HB_TAG('b','y','v',' '), HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ + {HB_TAG('b','z','c',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','z','j',' '), HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ + {HB_TAG('b','z','k',' '), HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ + {HB_TAG('c','a','a',' '), HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ + {HB_TAG('c','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ + {HB_TAG('c','a','f',' '), HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ + {HB_TAG('c','a','f',' '), HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ + {HB_TAG('c','a','k',' '), HB_TAG('C','A','K',' ')}, /* Kaqchikel */ + {HB_TAG('c','a','k',' '), HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ + {HB_TAG('c','b','k',' '), HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ + {HB_TAG('c','b','k',' '), HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ + {HB_TAG('c','b','l',' '), HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ + {HB_TAG('c','c','l',' '), HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ + {HB_TAG('c','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ + {HB_TAG('c','c','o',' '), HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ + {HB_TAG('c','c','q',' '), HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ + {HB_TAG('c','d','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ +/*{HB_TAG('c','e','b',' '), HB_TAG('C','E','B',' ')},*/ /* Cebuano */ + {HB_TAG('c','e','k',' '), HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ + {HB_TAG('c','e','y',' '), HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ + {HB_TAG('c','f','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ + {HB_TAG('c','f','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ +/*{HB_TAG('c','g','g',' '), HB_TAG('C','G','G',' ')},*/ /* Chiga */ + {HB_TAG('c','h','f',' '), HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ + {HB_TAG('c','h','g',' '), HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ + {HB_TAG('c','h','h',' '), HB_TAG_NONE }, /* Chinook != Chattisgarhi */ + {HB_TAG('c','h','j',' '), HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ + {HB_TAG('c','h','k',' '), HB_TAG('C','H','K','0')}, /* Chuukese */ + {HB_TAG('c','h','m',' '), HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ + {HB_TAG('c','h','m',' '), HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ + {HB_TAG('c','h','n',' '), HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ +/*{HB_TAG('c','h','o',' '), HB_TAG('C','H','O',' ')},*/ /* Choctaw */ + {HB_TAG('c','h','p',' '), HB_TAG('C','H','P',' ')}, /* Chipewyan */ + {HB_TAG('c','h','p',' '), HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ + {HB_TAG('c','h','p',' '), HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ + {HB_TAG('c','h','q',' '), HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ +/*{HB_TAG('c','h','r',' '), HB_TAG('C','H','R',' ')},*/ /* Cherokee */ +/*{HB_TAG('c','h','y',' '), HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ + {HB_TAG('c','h','z',' '), HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ + {HB_TAG('c','i','w',' '), HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ +/*{HB_TAG('c','j','a',' '), HB_TAG('C','J','A',' ')},*/ /* Western Cham */ +/*{HB_TAG('c','j','m',' '), HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ + {HB_TAG('c','j','y',' '), HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ + {HB_TAG('c','k','a',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ + {HB_TAG('c','k','b',' '), HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ + {HB_TAG('c','k','n',' '), HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ + {HB_TAG('c','k','s',' '), HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ + {HB_TAG('c','k','t',' '), HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ + {HB_TAG('c','k','z',' '), HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ + {HB_TAG('c','l','c',' '), HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ + {HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ + {HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ + {HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ + {HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ + {HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ + {HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ + {HB_TAG('c','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ + {HB_TAG('c','n','h',' '), HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ + {HB_TAG('c','n','k',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ + {HB_TAG('c','n','l',' '), HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ + {HB_TAG('c','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','n','r',' '), HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ + {HB_TAG('c','n','t',' '), HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ + {HB_TAG('c','n','u',' '), HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ + {HB_TAG('c','n','w',' '), HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ + {HB_TAG('c','o','a',' '), HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ + {HB_TAG('c','o','b',' '), HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ +/*{HB_TAG('c','o','p',' '), HB_TAG('C','O','P',' ')},*/ /* Coptic */ + {HB_TAG('c','o','q',' '), HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ + {HB_TAG('c','p','a',' '), HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ + {HB_TAG('c','p','e',' '), HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','f',' '), HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','i',' '), HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ +/*{HB_TAG('c','p','p',' '), HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','x',' '), HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ + {HB_TAG('c','q','d',' '), HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ + {HB_TAG('c','r','h',' '), HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {HB_TAG('c','r','i',' '), HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ + {HB_TAG('c','r','j',' '), HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('M','C','R',' ')}, /* Moose Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ + {HB_TAG('c','r','p',' '), HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','r','r',' '), HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ + {HB_TAG('c','r','s',' '), HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ + {HB_TAG('c','r','t',' '), HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ + {HB_TAG('c','r','x',' '), HB_TAG('C','R','R',' ')}, /* Carrier */ + {HB_TAG('c','r','x',' '), HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ + {HB_TAG('c','s','a',' '), HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ +/*{HB_TAG('c','s','b',' '), HB_TAG('C','S','B',' ')},*/ /* Kashubian */ + {HB_TAG('c','s','h',' '), HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ + {HB_TAG('c','s','j',' '), HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ + {HB_TAG('c','s','l',' '), HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ + {HB_TAG('c','s','o',' '), HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ + {HB_TAG('c','s','p',' '), HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','s','v',' '), HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ + {HB_TAG('c','s','w',' '), HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ + {HB_TAG('c','s','y',' '), HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ + {HB_TAG('c','t','c',' '), HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ + {HB_TAG('c','t','d',' '), HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ + {HB_TAG('c','t','e',' '), HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ +/*{HB_TAG('c','t','g',' '), HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ + {HB_TAG('c','t','h',' '), HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ + {HB_TAG('c','t','l',' '), HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {HB_TAG('c','t','s',' '), HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ +/*{HB_TAG('c','t','t',' '), HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ + {HB_TAG('c','t','u',' '), HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ + {HB_TAG('c','u','c',' '), HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ +/*{HB_TAG('c','u','k',' '), HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ + {HB_TAG('c','v','n',' '), HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ + {HB_TAG('c','w','d',' '), HB_TAG('D','C','R',' ')}, /* Woods Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ + {HB_TAG('c','z','h',' '), HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','t',' '), HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ +/*{HB_TAG('d','a','g',' '), HB_TAG('D','A','G',' ')},*/ /* Dagbani */ + {HB_TAG('d','a','o',' '), HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ + {HB_TAG('d','a','p',' '), HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ +/*{HB_TAG('d','a','r',' '), HB_TAG('D','A','R',' ')},*/ /* Dargwa */ +/*{HB_TAG('d','a','x',' '), HB_TAG('D','A','X',' ')},*/ /* Dayi */ + {HB_TAG('d','c','r',' '), HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ + {HB_TAG('d','e','n',' '), HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {HB_TAG('d','e','n',' '), HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + {HB_TAG('d','e','p',' '), HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ + {HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ + {HB_TAG('d','h','d',' '), HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ +/*{HB_TAG('d','h','g',' '), HB_TAG('D','H','G',' ')},*/ /* Dhangu */ + {HB_TAG('d','h','v',' '), HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','i','b',' '), HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ + {HB_TAG('d','i','k',' '), HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ + {HB_TAG('d','i','n',' '), HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ + {HB_TAG('d','i','p',' '), HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ + {HB_TAG('d','i','q',' '), HB_TAG('D','I','Q',' ')}, /* Dimli */ + {HB_TAG('d','i','q',' '), HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ + {HB_TAG('d','i','w',' '), HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ + {HB_TAG('d','j','e',' '), HB_TAG('D','J','R',' ')}, /* Zarma */ + {HB_TAG('d','j','k',' '), HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ + {HB_TAG('d','j','r',' '), HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ + {HB_TAG('d','k','s',' '), HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ + {HB_TAG('d','n','g',' '), HB_TAG('D','U','N',' ')}, /* Dungan */ +/*{HB_TAG('d','n','j',' '), HB_TAG('D','N','J',' ')},*/ /* Dan */ + {HB_TAG('d','n','k',' '), HB_TAG_NONE }, /* Dengka != Dinka */ + {HB_TAG('d','o','i',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ + {HB_TAG('d','r','h',' '), HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ + {HB_TAG('d','r','i',' '), HB_TAG_NONE }, /* C'Lela != Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ + {HB_TAG('d','s','b',' '), HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ + {HB_TAG('d','t','y',' '), HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ +/*{HB_TAG('d','u','j',' '), HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ + {HB_TAG('d','u','n',' '), HB_TAG_NONE }, /* Dusun Deyah != Dungan */ + {HB_TAG('d','u','p',' '), HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ + {HB_TAG('d','w','k',' '), HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ + {HB_TAG('d','w','u',' '), HB_TAG('D','U','J',' ')}, /* Dhuwal */ + {HB_TAG('d','w','y',' '), HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ + {HB_TAG('d','y','u',' '), HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ + {HB_TAG('d','z','n',' '), HB_TAG_NONE }, /* Dzando != Dzongkha */ + {HB_TAG('e','c','r',' '), HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ +/*{HB_TAG('e','f','i',' '), HB_TAG('E','F','I',' ')},*/ /* Efik */ + {HB_TAG('e','k','k',' '), HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ + {HB_TAG('e','k','y',' '), HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ + {HB_TAG('e','m','k',' '), HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ + {HB_TAG('e','m','k',' '), HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ + {HB_TAG('e','m','y',' '), HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ + {HB_TAG('e','n','b',' '), HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ + {HB_TAG('e','n','f',' '), HB_TAG('F','N','E',' ')}, /* Forest Enets */ + {HB_TAG('e','n','h',' '), HB_TAG('T','N','E',' ')}, /* Tundra Enets */ + {HB_TAG('e','s','g',' '), HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ + {HB_TAG('e','s','i',' '), HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ + {HB_TAG('e','s','k',' '), HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ +/*{HB_TAG('e','s','u',' '), HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ + {HB_TAG('e','t','o',' '), HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ + {HB_TAG('e','u','q',' '), HB_TAG_NONE }, /* Basque [collection] != Basque */ + {HB_TAG('e','v','e',' '), HB_TAG('E','V','N',' ')}, /* Even */ + {HB_TAG('e','v','n',' '), HB_TAG('E','V','K',' ')}, /* Evenki */ + {HB_TAG('e','w','o',' '), HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ + {HB_TAG('e','y','o',' '), HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ + {HB_TAG('f','a','b',' '), HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ + {HB_TAG('f','a','n',' '), HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ + {HB_TAG('f','a','n',' '), HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ + {HB_TAG('f','a','r',' '), HB_TAG_NONE }, /* Fataleka != Persian */ + {HB_TAG('f','a','t',' '), HB_TAG('F','A','T',' ')}, /* Fanti */ + {HB_TAG('f','a','t',' '), HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ + {HB_TAG('f','b','l',' '), HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ + {HB_TAG('f','f','m',' '), HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ + {HB_TAG('f','i','l',' '), HB_TAG('P','I','L',' ')}, /* Filipino */ + {HB_TAG('f','l','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ + {HB_TAG('f','l','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ + {HB_TAG('f','m','p',' '), HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ + {HB_TAG('f','m','p',' '), HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ + {HB_TAG('f','n','g',' '), HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ +/*{HB_TAG('f','o','n',' '), HB_TAG('F','O','N',' ')},*/ /* Fon */ + {HB_TAG('f','o','s',' '), HB_TAG_NONE }, /* Siraya != Faroese */ + {HB_TAG('f','p','e',' '), HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ +/*{HB_TAG('f','r','c',' '), HB_TAG('F','R','C',' ')},*/ /* Cajun French */ +/*{HB_TAG('f','r','p',' '), HB_TAG('F','R','P',' ')},*/ /* Arpitan */ + {HB_TAG('f','u','b',' '), HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ + {HB_TAG('f','u','c',' '), HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ + {HB_TAG('f','u','e',' '), HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ + {HB_TAG('f','u','f',' '), HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ + {HB_TAG('f','u','f',' '), HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ + {HB_TAG('f','u','h',' '), HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','i',' '), HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ + {HB_TAG('f','u','q',' '), HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','r',' '), HB_TAG('F','R','L',' ')}, /* Friulian */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ + {HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */ + {HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ + {HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */ + {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ +/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */ + {HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */ + {HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ + {HB_TAG('g','a','r',' '), HB_TAG_NONE }, /* Galeya != Garshuni */ + {HB_TAG('g','a','w',' '), HB_TAG_NONE }, /* Nobonob != Garhwali */ + {HB_TAG('g','a','x',' '), HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {HB_TAG('g','a','z',' '), HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ + {HB_TAG('g','b','m',' '), HB_TAG('G','A','W',' ')}, /* Garhwali */ + {HB_TAG('g','c','e',' '), HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ + {HB_TAG('g','c','f',' '), HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ + {HB_TAG('g','c','l',' '), HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ + {HB_TAG('g','c','r',' '), HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ + {HB_TAG('g','d','a',' '), HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ +/*{HB_TAG('g','e','z',' '), HB_TAG('G','E','Z',' ')},*/ /* Geez */ + {HB_TAG('g','g','o',' '), HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ + {HB_TAG('g','h','a',' '), HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ + {HB_TAG('g','h','k',' '), HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ + {HB_TAG('g','h','o',' '), HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ + {HB_TAG('g','i','b',' '), HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ +/*{HB_TAG('g','i','h',' '), HB_TAG('G','I','H',' ')},*/ /* Githabul */ + {HB_TAG('g','i','l',' '), HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ + {HB_TAG('g','j','u',' '), HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ + {HB_TAG('g','k','p',' '), HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {HB_TAG('g','k','p',' '), HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ + {HB_TAG('g','l','d',' '), HB_TAG('N','A','N',' ')}, /* Nanai */ +/*{HB_TAG('g','l','k',' '), HB_TAG('G','L','K',' ')},*/ /* Gilaki */ + {HB_TAG('g','m','z',' '), HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ + {HB_TAG('g','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ +/*{HB_TAG('g','n','n',' '), HB_TAG('G','N','N',' ')},*/ /* Gumatj */ + {HB_TAG('g','n','o',' '), HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ + {HB_TAG('g','n','w',' '), HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ +/*{HB_TAG('g','o','g',' '), HB_TAG('G','O','G',' ')},*/ /* Gogo */ + {HB_TAG('g','o','m',' '), HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ +/*{HB_TAG('g','o','n',' '), HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ + {HB_TAG('g','o','q',' '), HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ + {HB_TAG('g','o','x',' '), HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ + {HB_TAG('g','p','e',' '), HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ + {HB_TAG('g','r','o',' '), HB_TAG_NONE }, /* Groma != Garo */ + {HB_TAG('g','r','r',' '), HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ + {HB_TAG('g','r','t',' '), HB_TAG('G','R','O',' ')}, /* Garo */ + {HB_TAG('g','r','u',' '), HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ + {HB_TAG('g','s','w',' '), HB_TAG('A','L','S',' ')}, /* Alsatian */ + {HB_TAG('g','u','a',' '), HB_TAG_NONE }, /* Shiki != Guarani */ +/*{HB_TAG('g','u','c',' '), HB_TAG('G','U','C',' ')},*/ /* Wayuu */ +/*{HB_TAG('g','u','f',' '), HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ + {HB_TAG('g','u','g',' '), HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ + {HB_TAG('g','u','i',' '), HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ + {HB_TAG('g','u','k',' '), HB_TAG('G','M','Z',' ')}, /* Gumuz */ + {HB_TAG('g','u','l',' '), HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ + {HB_TAG('g','u','n',' '), HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ +/*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */ + {HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ + {HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ + {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ + {HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ + {HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ + {HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ + {HB_TAG('h','a','l',' '), HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ + {HB_TAG('h','a','r',' '), HB_TAG('H','R','I',' ')}, /* Harari */ +/*{HB_TAG('h','a','w',' '), HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ + {HB_TAG('h','a','x',' '), HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ +/*{HB_TAG('h','a','y',' '), HB_TAG('H','A','Y',' ')},*/ /* Haya */ +/*{HB_TAG('h','a','z',' '), HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ + {HB_TAG('h','b','n',' '), HB_TAG_NONE }, /* Heiban != Hammer-Banna */ + {HB_TAG('h','c','a',' '), HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ + {HB_TAG('h','d','n',' '), HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ + {HB_TAG('h','e','a',' '), HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ +/*{HB_TAG('h','e','i',' '), HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ +/*{HB_TAG('h','i','l',' '), HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ + {HB_TAG('h','j','i',' '), HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ + {HB_TAG('h','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ + {HB_TAG('h','m','a',' '), HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','c',' '), HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ + {HB_TAG('h','m','e',' '), HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','g',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','h',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','i',' '), HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','j',' '), HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ + {HB_TAG('h','m','l',' '), HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ + {HB_TAG('h','m','m',' '), HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ +/*{HB_TAG('h','m','n',' '), HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ + {HB_TAG('h','m','p',' '), HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ + {HB_TAG('h','m','s',' '), HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','w',' '), HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ + {HB_TAG('h','m','y',' '), HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ +/*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ + {HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ + {HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ + {HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ + {HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */ + {HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ + {HB_TAG('h','o','j',' '), HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ + {HB_TAG('h','o','j',' '), HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ + {HB_TAG('h','r','a',' '), HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ + {HB_TAG('h','r','m',' '), HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ + {HB_TAG('h','s','b',' '), HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ + {HB_TAG('h','s','n',' '), HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ + {HB_TAG('h','u','j',' '), HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ + {HB_TAG('h','u','p',' '), HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ + {HB_TAG('h','u','s',' '), HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ + {HB_TAG('h','w','c',' '), HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ + {HB_TAG('h','y','w',' '), HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ +/*{HB_TAG('i','b','a',' '), HB_TAG('I','B','A',' ')},*/ /* Iban */ +/*{HB_TAG('i','b','b',' '), HB_TAG('I','B','B',' ')},*/ /* Ibibio */ + {HB_TAG('i','b','y',' '), HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ + {HB_TAG('i','c','r',' '), HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ + {HB_TAG('i','d','a',' '), HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ + {HB_TAG('i','d','b',' '), HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ + {HB_TAG('i','g','b',' '), HB_TAG('E','B','I',' ')}, /* Ebira */ + {HB_TAG('i','h','b',' '), HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ + {HB_TAG('i','j','c',' '), HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ + {HB_TAG('i','j','e',' '), HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ + {HB_TAG('i','j','n',' '), HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ +/*{HB_TAG('i','j','o',' '), HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ + {HB_TAG('i','j','s',' '), HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ + {HB_TAG('i','k','t',' '), HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ +/*{HB_TAG('i','l','o',' '), HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ + {HB_TAG('i','n','g',' '), HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ + {HB_TAG('i','n','h',' '), HB_TAG('I','N','G',' ')}, /* Ingush */ + {HB_TAG('i','r','i',' '), HB_TAG_NONE }, /* Rigwe != Irish */ +/*{HB_TAG('i','r','u',' '), HB_TAG('I','R','U',' ')},*/ /* Irula */ + {HB_TAG('i','s','m',' '), HB_TAG_NONE }, /* Masimasi != Inari Sami */ + {HB_TAG('i','t','z',' '), HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ + {HB_TAG('i','x','l',' '), HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ + {HB_TAG('j','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ + {HB_TAG('j','a','k',' '), HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ + {HB_TAG('j','a','m',' '), HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ + {HB_TAG('j','a','m',' '), HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ + {HB_TAG('j','a','n',' '), HB_TAG_NONE }, /* Jandai != Japanese */ + {HB_TAG('j','a','x',' '), HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ + {HB_TAG('j','b','e',' '), HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ + {HB_TAG('j','b','n',' '), HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ +/*{HB_TAG('j','b','o',' '), HB_TAG('J','B','O',' ')},*/ /* Lojban */ +/*{HB_TAG('j','c','t',' '), HB_TAG('J','C','T',' ')},*/ /* Krymchak */ + {HB_TAG('j','g','o',' '), HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ + {HB_TAG('j','i','i',' '), HB_TAG_NONE }, /* Jiiddu != Yiddish */ + {HB_TAG('j','k','m',' '), HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ + {HB_TAG('j','k','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ + {HB_TAG('j','u','d',' '), HB_TAG_NONE }, /* Worodougou != Ladino */ + {HB_TAG('j','u','l',' '), HB_TAG_NONE }, /* Jirel != Jula */ + {HB_TAG('j','v','d',' '), HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ + {HB_TAG('k','a','a',' '), HB_TAG('K','R','K',' ')}, /* Karakalpak */ + {HB_TAG('k','a','b',' '), HB_TAG('K','A','B','0')}, /* Kabyle */ + {HB_TAG('k','a','b',' '), HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ + {HB_TAG('k','a','c',' '), HB_TAG_NONE }, /* Kachin != Kachchi */ + {HB_TAG('k','a','m',' '), HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ + {HB_TAG('k','a','r',' '), HB_TAG('K','R','N',' ')}, /* Karen [collection] */ +/*{HB_TAG('k','a','w',' '), HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ + {HB_TAG('k','b','d',' '), HB_TAG('K','A','B',' ')}, /* Kabardian */ + {HB_TAG('k','b','y',' '), HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ + {HB_TAG('k','c','n',' '), HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ +/*{HB_TAG('k','d','e',' '), HB_TAG('K','D','E',' ')},*/ /* Makonde */ + {HB_TAG('k','d','r',' '), HB_TAG('K','R','M',' ')}, /* Karaim */ + {HB_TAG('k','d','t',' '), HB_TAG('K','U','Y',' ')}, /* Kuy */ + {HB_TAG('k','e','a',' '), HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ + {HB_TAG('k','e','a',' '), HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ + {HB_TAG('k','e','b',' '), HB_TAG_NONE }, /* Kélé != Kebena */ + {HB_TAG('k','e','k',' '), HB_TAG('K','E','K',' ')}, /* Kekchi */ + {HB_TAG('k','e','k',' '), HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ + {HB_TAG('k','e','x',' '), HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ + {HB_TAG('k','f','a',' '), HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ + {HB_TAG('k','f','r',' '), HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ + {HB_TAG('k','f','x',' '), HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ + {HB_TAG('k','f','y',' '), HB_TAG('K','M','N',' ')}, /* Kumaoni */ + {HB_TAG('k','g','e',' '), HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ + {HB_TAG('k','h','a',' '), HB_TAG('K','S','I',' ')}, /* Khasi */ + {HB_TAG('k','h','b',' '), HB_TAG('X','B','D',' ')}, /* Lü */ + {HB_TAG('k','h','k',' '), HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ + {HB_TAG('k','h','n',' '), HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','s',' '), HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','v',' '), HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ +/*{HB_TAG('k','h','w',' '), HB_TAG('K','H','W',' ')},*/ /* Khowar */ + {HB_TAG('k','i','s',' '), HB_TAG_NONE }, /* Kis != Kisii */ + {HB_TAG('k','i','u',' '), HB_TAG('K','I','U',' ')}, /* Kirmanjki */ + {HB_TAG('k','i','u',' '), HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ + {HB_TAG('k','j','b',' '), HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ +/*{HB_TAG('k','j','d',' '), HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ + {HB_TAG('k','j','h',' '), HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ + {HB_TAG('k','j','p',' '), HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {HB_TAG('k','j','p',' '), HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ + {HB_TAG('k','j','t',' '), HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ +/*{HB_TAG('k','j','z',' '), HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ + {HB_TAG('k','k','n',' '), HB_TAG_NONE }, /* Kon Keu != Kokni */ + {HB_TAG('k','k','z',' '), HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ + {HB_TAG('k','l','m',' '), HB_TAG_NONE }, /* Migum != Kalmyk */ + {HB_TAG('k','l','n',' '), HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ + {HB_TAG('k','m','b',' '), HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ + {HB_TAG('k','m','n',' '), HB_TAG_NONE }, /* Awtuw != Kumaoni */ + {HB_TAG('k','m','o',' '), HB_TAG_NONE }, /* Kwoma != Komo */ + {HB_TAG('k','m','r',' '), HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ + {HB_TAG('k','m','s',' '), HB_TAG_NONE }, /* Kamasau != Komso */ + {HB_TAG('k','m','v',' '), HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ + {HB_TAG('k','m','w',' '), HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ +/*{HB_TAG('k','m','z',' '), HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ + {HB_TAG('k','n','c',' '), HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ + {HB_TAG('k','n','g',' '), HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ + {HB_TAG('k','n','j',' '), HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ + {HB_TAG('k','n','n',' '), HB_TAG('K','O','K',' ')}, /* Konkani */ + {HB_TAG('k','n','r',' '), HB_TAG_NONE }, /* Kaningra != Kanuri */ + {HB_TAG('k','o','d',' '), HB_TAG_NONE }, /* Kodi != Kodagu */ + {HB_TAG('k','o','h',' '), HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ +/*{HB_TAG('k','o','k',' '), HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ + {HB_TAG('k','o','p',' '), HB_TAG_NONE }, /* Waube != Komi-Permyak */ +/*{HB_TAG('k','o','s',' '), HB_TAG('K','O','S',' ')},*/ /* Kosraean */ + {HB_TAG('k','o','y',' '), HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ + {HB_TAG('k','o','z',' '), HB_TAG_NONE }, /* Korak != Komi-Zyrian */ + {HB_TAG('k','p','e',' '), HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ + {HB_TAG('k','p','l',' '), HB_TAG_NONE }, /* Kpala != Kpelle */ + {HB_TAG('k','p','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ + {HB_TAG('k','p','y',' '), HB_TAG('K','Y','K',' ')}, /* Koryak */ + {HB_TAG('k','q','s',' '), HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ + {HB_TAG('k','q','y',' '), HB_TAG('K','R','T',' ')}, /* Koorete */ + {HB_TAG('k','r','c',' '), HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ + {HB_TAG('k','r','c',' '), HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ + {HB_TAG('k','r','i',' '), HB_TAG('K','R','I',' ')}, /* Krio */ + {HB_TAG('k','r','i',' '), HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ + {HB_TAG('k','r','k',' '), HB_TAG_NONE }, /* Kerek != Karakalpak */ +/*{HB_TAG('k','r','l',' '), HB_TAG('K','R','L',' ')},*/ /* Karelian */ + {HB_TAG('k','r','m',' '), HB_TAG_NONE }, /* Krim (retired code) != Karaim */ + {HB_TAG('k','r','n',' '), HB_TAG_NONE }, /* Sapo != Karen */ + {HB_TAG('k','r','t',' '), HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ + {HB_TAG('k','r','u',' '), HB_TAG('K','U','U',' ')}, /* Kurukh */ + {HB_TAG('k','s','h',' '), HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ + {HB_TAG('k','s','i',' '), HB_TAG_NONE }, /* Krisa != Khasi */ + {HB_TAG('k','s','m',' '), HB_TAG_NONE }, /* Kumba != Kildin Sami */ + {HB_TAG('k','s','s',' '), HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ + {HB_TAG('k','s','w',' '), HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ + {HB_TAG('k','s','w',' '), HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ + {HB_TAG('k','t','b',' '), HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ + {HB_TAG('k','t','u',' '), HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {HB_TAG('k','t','w',' '), HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ + {HB_TAG('k','u','i',' '), HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ + {HB_TAG('k','u','l',' '), HB_TAG_NONE }, /* Kulere != Kulvi */ +/*{HB_TAG('k','u','m',' '), HB_TAG('K','U','M',' ')},*/ /* Kumyk */ + {HB_TAG('k','u','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ + {HB_TAG('k','u','w',' '), HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ + {HB_TAG('k','u','y',' '), HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ + {HB_TAG('k','v','b',' '), HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ + {HB_TAG('k','v','l',' '), HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ + {HB_TAG('k','v','q',' '), HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ + {HB_TAG('k','v','r',' '), HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ + {HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ + {HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ + {HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ +/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ + {HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ + {HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ + {HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ + {HB_TAG('k','x','d',' '), HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ + {HB_TAG('k','x','f',' '), HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ + {HB_TAG('k','x','k',' '), HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ + {HB_TAG('k','x','l',' '), HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ + {HB_TAG('k','x','u',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ + {HB_TAG('k','y','k',' '), HB_TAG_NONE }, /* Kamayo != Koryak */ + {HB_TAG('k','y','u',' '), HB_TAG('K','Y','U',' ')}, /* Western Kayah */ + {HB_TAG('k','y','u',' '), HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ + {HB_TAG('l','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ + {HB_TAG('l','a','d',' '), HB_TAG('J','U','D',' ')}, /* Ladino */ + {HB_TAG('l','a','h',' '), HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ + {HB_TAG('l','a','k',' '), HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ + {HB_TAG('l','a','m',' '), HB_TAG_NONE }, /* Lamba != Lambani */ + {HB_TAG('l','a','z',' '), HB_TAG_NONE }, /* Aribwatsa != Laz */ + {HB_TAG('l','b','e',' '), HB_TAG('L','A','K',' ')}, /* Lak */ + {HB_TAG('l','b','j',' '), HB_TAG('L','D','K',' ')}, /* Ladakhi */ + {HB_TAG('l','b','l',' '), HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ + {HB_TAG('l','c','e',' '), HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ + {HB_TAG('l','c','f',' '), HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ + {HB_TAG('l','d','i',' '), HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ + {HB_TAG('l','d','k',' '), HB_TAG_NONE }, /* Leelau != Ladakhi */ +/*{HB_TAG('l','e','f',' '), HB_TAG('L','E','F',' ')},*/ /* Lelemi */ +/*{HB_TAG('l','e','z',' '), HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ + {HB_TAG('l','i','f',' '), HB_TAG('L','M','B',' ')}, /* Limbu */ +/*{HB_TAG('l','i','j',' '), HB_TAG('L','I','J',' ')},*/ /* Ligurian */ + {HB_TAG('l','i','r',' '), HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ +/*{HB_TAG('l','i','s',' '), HB_TAG('L','I','S',' ')},*/ /* Lisu */ + {HB_TAG('l','i','w',' '), HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ + {HB_TAG('l','i','y',' '), HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ +/*{HB_TAG('l','j','p',' '), HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ + {HB_TAG('l','k','b',' '), HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ +/*{HB_TAG('l','k','i',' '), HB_TAG('L','K','I',' ')},*/ /* Laki */ + {HB_TAG('l','k','o',' '), HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ + {HB_TAG('l','k','s',' '), HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ + {HB_TAG('l','l','d',' '), HB_TAG('L','A','D',' ')}, /* Ladin */ + {HB_TAG('l','m','a',' '), HB_TAG_NONE }, /* East Limba != Low Mari */ + {HB_TAG('l','m','b',' '), HB_TAG_NONE }, /* Merei != Limbu */ + {HB_TAG('l','m','n',' '), HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ +/*{HB_TAG('l','m','o',' '), HB_TAG('L','M','O',' ')},*/ /* Lombard */ + {HB_TAG('l','m','w',' '), HB_TAG_NONE }, /* Lake Miwok != Lomwe */ + {HB_TAG('l','n','a',' '), HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ + {HB_TAG('l','n','l',' '), HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ +/*{HB_TAG('l','o','m',' '), HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ + {HB_TAG('l','o','u',' '), HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ +/*{HB_TAG('l','p','o',' '), HB_TAG('L','P','O',' ')},*/ /* Lipo */ +/*{HB_TAG('l','r','c',' '), HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ + {HB_TAG('l','r','i',' '), HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ + {HB_TAG('l','r','m',' '), HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ + {HB_TAG('l','r','t',' '), HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ + {HB_TAG('l','s','b',' '), HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ + {HB_TAG('l','s','m',' '), HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ + {HB_TAG('l','t','g',' '), HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ + {HB_TAG('l','t','h',' '), HB_TAG_NONE }, /* Thur != Lithuanian */ + {HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ + {HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ +/*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ +/*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ + {HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ + {HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ + {HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ + {HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ + {HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */ + {HB_TAG('l','v','s',' '), HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ + {HB_TAG('l','w','g',' '), HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ + {HB_TAG('l','z','h',' '), HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ + {HB_TAG('l','z','z',' '), HB_TAG('L','A','Z',' ')}, /* Laz */ +/*{HB_TAG('m','a','d',' '), HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ +/*{HB_TAG('m','a','g',' '), HB_TAG('M','A','G',' ')},*/ /* Magahi */ + {HB_TAG('m','a','i',' '), HB_TAG('M','T','H',' ')}, /* Maithili */ + {HB_TAG('m','a','j',' '), HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ + {HB_TAG('m','a','k',' '), HB_TAG('M','K','R',' ')}, /* Makasar */ + {HB_TAG('m','a','m',' '), HB_TAG('M','A','M',' ')}, /* Mam */ + {HB_TAG('m','a','m',' '), HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ + {HB_TAG('m','a','n',' '), HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ + {HB_TAG('m','a','p',' '), HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ + {HB_TAG('m','a','w',' '), HB_TAG_NONE }, /* Mampruli != Marwari */ + {HB_TAG('m','a','x',' '), HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ + {HB_TAG('m','a','x',' '), HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ + {HB_TAG('m','b','f',' '), HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ + {HB_TAG('m','b','n',' '), HB_TAG_NONE }, /* Macaguán != Mbundu */ +/*{HB_TAG('m','b','o',' '), HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ + {HB_TAG('m','c','h',' '), HB_TAG_NONE }, /* Maquiritari != Manchu */ + {HB_TAG('m','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ + {HB_TAG('m','c','r',' '), HB_TAG_NONE }, /* Menya != Moose Cree */ + {HB_TAG('m','c','t',' '), HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ + {HB_TAG('m','d','e',' '), HB_TAG_NONE }, /* Maba (Chad) != Mende */ + {HB_TAG('m','d','f',' '), HB_TAG('M','O','K',' ')}, /* Moksha */ +/*{HB_TAG('m','d','r',' '), HB_TAG('M','D','R',' ')},*/ /* Mandar */ + {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ + {HB_TAG('m','e','n',' '), HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ + {HB_TAG('m','e','o',' '), HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ +/*{HB_TAG('m','e','r',' '), HB_TAG('M','E','R',' ')},*/ /* Meru */ + {HB_TAG('m','f','a',' '), HB_TAG('M','F','A',' ')}, /* Pattani Malay */ + {HB_TAG('m','f','a',' '), HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ + {HB_TAG('m','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ + {HB_TAG('m','f','e',' '), HB_TAG('M','F','E',' ')}, /* Morisyen */ + {HB_TAG('m','f','e',' '), HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ + {HB_TAG('m','f','p',' '), HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ + {HB_TAG('m','h','c',' '), HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ + {HB_TAG('m','h','r',' '), HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ + {HB_TAG('m','h','v',' '), HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ + {HB_TAG('m','i','n',' '), HB_TAG('M','I','N',' ')}, /* Minangkabau */ + {HB_TAG('m','i','n',' '), HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ + {HB_TAG('m','i','z',' '), HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ + {HB_TAG('m','k','n',' '), HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ + {HB_TAG('m','k','r',' '), HB_TAG_NONE }, /* Malas != Makasar */ + {HB_TAG('m','k','u',' '), HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ +/*{HB_TAG('m','k','w',' '), HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ + {HB_TAG('m','l','e',' '), HB_TAG_NONE }, /* Manambu != Male */ + {HB_TAG('m','l','n',' '), HB_TAG_NONE }, /* Malango != Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ + {HB_TAG('m','l','r',' '), HB_TAG_NONE }, /* Vame != Malayalam Reformed */ + {HB_TAG('m','m','r',' '), HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ + {HB_TAG('m','n','c',' '), HB_TAG('M','C','H',' ')}, /* Manchu */ + {HB_TAG('m','n','d',' '), HB_TAG_NONE }, /* Mondé != Mandinka */ + {HB_TAG('m','n','g',' '), HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ + {HB_TAG('m','n','h',' '), HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ +/*{HB_TAG('m','n','i',' '), HB_TAG('M','N','I',' ')},*/ /* Manipuri */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','D',' ')}, /* Mandinka */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ + {HB_TAG('m','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ + {HB_TAG('m','n','s',' '), HB_TAG('M','A','N',' ')}, /* Mansi */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N',' ')}, /* Mon */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ + {HB_TAG('m','n','x',' '), HB_TAG_NONE }, /* Manikion != Manx */ + {HB_TAG('m','o','d',' '), HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ +/*{HB_TAG('m','o','h',' '), HB_TAG('M','O','H',' ')},*/ /* Mohawk */ + {HB_TAG('m','o','k',' '), HB_TAG_NONE }, /* Morori != Moksha */ + {HB_TAG('m','o','p',' '), HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ + {HB_TAG('m','o','r',' '), HB_TAG_NONE }, /* Moro != Moroccan */ +/*{HB_TAG('m','o','s',' '), HB_TAG('M','O','S',' ')},*/ /* Mossi */ + {HB_TAG('m','p','e',' '), HB_TAG('M','A','J',' ')}, /* Majang */ + {HB_TAG('m','q','g',' '), HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ + {HB_TAG('m','r','h',' '), HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ + {HB_TAG('m','r','j',' '), HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ + {HB_TAG('m','s','c',' '), HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ + {HB_TAG('m','s','h',' '), HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ + {HB_TAG('m','s','i',' '), HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ + {HB_TAG('m','s','i',' '), HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ + {HB_TAG('m','t','h',' '), HB_TAG_NONE }, /* Munggui != Maithili */ + {HB_TAG('m','t','r',' '), HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ + {HB_TAG('m','t','s',' '), HB_TAG_NONE }, /* Yora != Maltese */ + {HB_TAG('m','u','d',' '), HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ + {HB_TAG('m','u','i',' '), HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ + {HB_TAG('m','u','n',' '), HB_TAG_NONE }, /* Munda [collection] != Mundari */ + {HB_TAG('m','u','p',' '), HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ + {HB_TAG('m','u','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ +/*{HB_TAG('m','u','s',' '), HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ + {HB_TAG('m','v','b',' '), HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ + {HB_TAG('m','v','e',' '), HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ + {HB_TAG('m','v','f',' '), HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ + {HB_TAG('m','w','k',' '), HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ +/*{HB_TAG('m','w','l',' '), HB_TAG('M','W','L',' ')},*/ /* Mirandese */ + {HB_TAG('m','w','q',' '), HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ + {HB_TAG('m','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ + {HB_TAG('m','w','w',' '), HB_TAG('M','W','W',' ')}, /* Hmong Daw */ + {HB_TAG('m','w','w',' '), HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ + {HB_TAG('m','y','m',' '), HB_TAG('M','E','N',' ')}, /* Me’en */ +/*{HB_TAG('m','y','n',' '), HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ + {HB_TAG('m','y','q',' '), HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ + {HB_TAG('m','y','v',' '), HB_TAG('E','R','Z',' ')}, /* Erzya */ + {HB_TAG('m','z','b',' '), HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ +/*{HB_TAG('m','z','n',' '), HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ + {HB_TAG('m','z','s',' '), HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ + {HB_TAG('n','a','g',' '), HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ + {HB_TAG('n','a','g',' '), HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ +/*{HB_TAG('n','a','h',' '), HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ + {HB_TAG('n','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ +/*{HB_TAG('n','a','p',' '), HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ + {HB_TAG('n','a','s',' '), HB_TAG_NONE }, /* Naasioi != Naskapi */ + {HB_TAG('n','a','z',' '), HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ + {HB_TAG('n','c','h',' '), HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','c','i',' '), HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ + {HB_TAG('n','c','j',' '), HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','c','l',' '), HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ + {HB_TAG('n','c','r',' '), HB_TAG_NONE }, /* Ncane != N-Cree */ + {HB_TAG('n','c','x',' '), HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','d','b',' '), HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ +/*{HB_TAG('n','d','c',' '), HB_TAG('N','D','C',' ')},*/ /* Ndau */ + {HB_TAG('n','d','g',' '), HB_TAG_NONE }, /* Ndengereko != Ndonga */ +/*{HB_TAG('n','d','s',' '), HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ + {HB_TAG('n','e','f',' '), HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ +/*{HB_TAG('n','e','w',' '), HB_TAG('N','E','W',' ')},*/ /* Newari */ +/*{HB_TAG('n','g','a',' '), HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ + {HB_TAG('n','g','l',' '), HB_TAG('L','M','W',' ')}, /* Lomwe */ + {HB_TAG('n','g','m',' '), HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ + {HB_TAG('n','g','o',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ + {HB_TAG('n','g','r',' '), HB_TAG_NONE }, /* Engdewu != Nagari */ + {HB_TAG('n','g','u',' '), HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ + {HB_TAG('n','h','c',' '), HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ + {HB_TAG('n','h','d',' '), HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ + {HB_TAG('n','h','e',' '), HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','g',' '), HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ + {HB_TAG('n','h','i',' '), HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ + {HB_TAG('n','h','k',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ + {HB_TAG('n','h','m',' '), HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ + {HB_TAG('n','h','n',' '), HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ + {HB_TAG('n','h','p',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','q',' '), HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','t',' '), HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','v',' '), HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','w',' '), HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','x',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','y',' '), HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','z',' '), HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ + {HB_TAG('n','i','q',' '), HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ + {HB_TAG('n','i','s',' '), HB_TAG_NONE }, /* Nimi != Nisi */ +/*{HB_TAG('n','i','u',' '), HB_TAG('N','I','U',' ')},*/ /* Niuean */ + {HB_TAG('n','i','v',' '), HB_TAG('G','I','L',' ')}, /* Gilyak */ + {HB_TAG('n','j','t',' '), HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ + {HB_TAG('n','j','z',' '), HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ + {HB_TAG('n','k','o',' '), HB_TAG_NONE }, /* Nkonya != N’Ko */ + {HB_TAG('n','k','x',' '), HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ + {HB_TAG('n','l','a',' '), HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ + {HB_TAG('n','l','e',' '), HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ + {HB_TAG('n','l','n',' '), HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ + {HB_TAG('n','l','v',' '), HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ + {HB_TAG('n','n','h',' '), HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ + {HB_TAG('n','n','z',' '), HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ + {HB_TAG('n','o','d',' '), HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ +/*{HB_TAG('n','o','e',' '), HB_TAG('N','O','E',' ')},*/ /* Nimadi */ +/*{HB_TAG('n','o','g',' '), HB_TAG('N','O','G',' ')},*/ /* Nogai */ +/*{HB_TAG('n','o','v',' '), HB_TAG('N','O','V',' ')},*/ /* Novial */ + {HB_TAG('n','p','i',' '), HB_TAG('N','E','P',' ')}, /* Nepali */ + {HB_TAG('n','p','l',' '), HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','q','o',' '), HB_TAG('N','K','O',' ')}, /* N’Ko */ + {HB_TAG('n','s','k',' '), HB_TAG('N','A','S',' ')}, /* Naskapi */ + {HB_TAG('n','s','m',' '), HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ +/*{HB_TAG('n','s','o',' '), HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ + {HB_TAG('n','s','u',' '), HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ + {HB_TAG('n','t','o',' '), HB_TAG_NONE }, /* Ntomba != Esperanto */ + {HB_TAG('n','u','e',' '), HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ + {HB_TAG('n','u','u',' '), HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ + {HB_TAG('n','u','z',' '), HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ + {HB_TAG('n','w','e',' '), HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ + {HB_TAG('n','y','d',' '), HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ +/*{HB_TAG('n','y','m',' '), HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ + {HB_TAG('n','y','n',' '), HB_TAG('N','K','L',' ')}, /* Nyankole */ +/*{HB_TAG('n','z','a',' '), HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ +/*{HB_TAG('o','j','b',' '), HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ + {HB_TAG('o','j','c',' '), HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ + {HB_TAG('o','j','g',' '), HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ + {HB_TAG('o','j','s',' '), HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ + {HB_TAG('o','j','s',' '), HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ + {HB_TAG('o','j','w',' '), HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ + {HB_TAG('o','k','d',' '), HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ + {HB_TAG('o','k','i',' '), HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ + {HB_TAG('o','k','m',' '), HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {HB_TAG('o','k','r',' '), HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ + {HB_TAG('o','n','x',' '), HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ + {HB_TAG('o','o','r',' '), HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ + {HB_TAG('o','r','c',' '), HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ + {HB_TAG('o','r','n',' '), HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ + {HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */ + {HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ + {HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ + {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ + {HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ + {HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ + {HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ +/*{HB_TAG('p','a','g',' '), HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ + {HB_TAG('p','a','l',' '), HB_TAG_NONE }, /* Pahlavi != Pali */ +/*{HB_TAG('p','a','m',' '), HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ + {HB_TAG('p','a','p',' '), HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ + {HB_TAG('p','a','p',' '), HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ + {HB_TAG('p','a','s',' '), HB_TAG_NONE }, /* Papasena != Pashto */ +/*{HB_TAG('p','a','u',' '), HB_TAG('P','A','U',' ')},*/ /* Palauan */ + {HB_TAG('p','b','t',' '), HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ + {HB_TAG('p','b','u',' '), HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ +/*{HB_TAG('p','c','c',' '), HB_TAG('P','C','C',' ')},*/ /* Bouyei */ +/*{HB_TAG('p','c','d',' '), HB_TAG('P','C','D',' ')},*/ /* Picard */ + {HB_TAG('p','c','e',' '), HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ + {HB_TAG('p','c','k',' '), HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ + {HB_TAG('p','c','m',' '), HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ +/*{HB_TAG('p','d','c',' '), HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ + {HB_TAG('p','d','u',' '), HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ + {HB_TAG('p','e','a',' '), HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ + {HB_TAG('p','e','l',' '), HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ + {HB_TAG('p','e','s',' '), HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ + {HB_TAG('p','e','y',' '), HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ + {HB_TAG('p','g','a',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ + {HB_TAG('p','g','a',' '), HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ +/*{HB_TAG('p','h','k',' '), HB_TAG('P','H','K',' ')},*/ /* Phake */ + {HB_TAG('p','i','h',' '), HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ + {HB_TAG('p','i','h',' '), HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ + {HB_TAG('p','i','l',' '), HB_TAG_NONE }, /* Yom != Filipino */ + {HB_TAG('p','i','s',' '), HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ + {HB_TAG('p','k','h',' '), HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ + {HB_TAG('p','k','o',' '), HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ + {HB_TAG('p','l','g',' '), HB_TAG_NONE }, /* Pilagá != Palaung */ + {HB_TAG('p','l','k',' '), HB_TAG_NONE }, /* Kohistani Shina != Polish */ + {HB_TAG('p','l','l',' '), HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ + {HB_TAG('p','l','n',' '), HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ + {HB_TAG('p','l','p',' '), HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ + {HB_TAG('p','l','t',' '), HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ + {HB_TAG('p','m','l',' '), HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ +/*{HB_TAG('p','m','s',' '), HB_TAG('P','M','S',' ')},*/ /* Piemontese */ + {HB_TAG('p','m','y',' '), HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ +/*{HB_TAG('p','n','b',' '), HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ + {HB_TAG('p','o','c',' '), HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ + {HB_TAG('p','o','h',' '), HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ + {HB_TAG('p','o','h',' '), HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ +/*{HB_TAG('p','o','n',' '), HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ + {HB_TAG('p','o','v',' '), HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ + {HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ + {HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ +/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */ + {HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ + {HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ + {HB_TAG('p','s','t',' '), HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ + {HB_TAG('p','u','b',' '), HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ + {HB_TAG('p','u','z',' '), HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ + {HB_TAG('p','w','o',' '), HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ + {HB_TAG('p','w','o',' '), HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ + {HB_TAG('p','w','w',' '), HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ + {HB_TAG('q','u','c',' '), HB_TAG('Q','U','C',' ')}, /* K’iche’ */ + {HB_TAG('q','u','c',' '), HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ + {HB_TAG('q','u','f',' '), HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','k',' '), HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','m',' '), HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ + {HB_TAG('q','u','v',' '), HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ + {HB_TAG('q','u','y',' '), HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ +/*{HB_TAG('q','u','z',' '), HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ + {HB_TAG('q','v','c',' '), HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ + {HB_TAG('q','v','e',' '), HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ + {HB_TAG('q','v','s',' '), HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ + {HB_TAG('q','w','c',' '), HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','t',' '), HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','p',' '), HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ + {HB_TAG('q','x','u',' '), HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ + {HB_TAG('r','a','g',' '), HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ +/*{HB_TAG('r','a','j',' '), HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ + {HB_TAG('r','a','l',' '), HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ +/*{HB_TAG('r','a','r',' '), HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ + {HB_TAG('r','b','b',' '), HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ + {HB_TAG('r','b','l',' '), HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ + {HB_TAG('r','c','f',' '), HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ +/*{HB_TAG('r','e','j',' '), HB_TAG('R','E','J',' ')},*/ /* Rejang */ +/*{HB_TAG('r','h','g',' '), HB_TAG('R','H','G',' ')},*/ /* Rohingya */ +/*{HB_TAG('r','i','a',' '), HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ + {HB_TAG('r','i','f',' '), HB_TAG('R','I','F',' ')}, /* Tarifit */ + {HB_TAG('r','i','f',' '), HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ +/*{HB_TAG('r','i','t',' '), HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ + {HB_TAG('r','k','i',' '), HB_TAG('A','R','K',' ')}, /* Rakhine */ +/*{HB_TAG('r','k','w',' '), HB_TAG('R','K','W',' ')},*/ /* Arakwal */ + {HB_TAG('r','m','c',' '), HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ + {HB_TAG('r','m','f',' '), HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ + {HB_TAG('r','m','l',' '), HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ + {HB_TAG('r','m','n',' '), HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ + {HB_TAG('r','m','o',' '), HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ + {HB_TAG('r','m','s',' '), HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ + {HB_TAG('r','m','w',' '), HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ + {HB_TAG('r','m','y',' '), HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ + {HB_TAG('r','m','y',' '), HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ + {HB_TAG('r','m','z',' '), HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ + {HB_TAG('r','o','m',' '), HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ + {HB_TAG('r','o','p',' '), HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ + {HB_TAG('r','t','c',' '), HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ +/*{HB_TAG('r','t','m',' '), HB_TAG('R','T','M',' ')},*/ /* Rotuman */ + {HB_TAG('r','u','e',' '), HB_TAG('R','S','Y',' ')}, /* Rusyn */ +/*{HB_TAG('r','u','p',' '), HB_TAG('R','U','P',' ')},*/ /* Aromanian */ + {HB_TAG('r','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari (India) */ + {HB_TAG('s','a','d',' '), HB_TAG_NONE }, /* Sandawe != Sadri */ + {HB_TAG('s','a','h',' '), HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ + {HB_TAG('s','a','m',' '), HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ +/*{HB_TAG('s','a','s',' '), HB_TAG('S','A','S',' ')},*/ /* Sasak */ +/*{HB_TAG('s','a','t',' '), HB_TAG('S','A','T',' ')},*/ /* Santali */ + {HB_TAG('s','a','y',' '), HB_TAG_NONE }, /* Saya != Sayisi */ + {HB_TAG('s','c','f',' '), HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ + {HB_TAG('s','c','h',' '), HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ + {HB_TAG('s','c','i',' '), HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ + {HB_TAG('s','c','k',' '), HB_TAG('S','A','D',' ')}, /* Sadri */ +/*{HB_TAG('s','c','n',' '), HB_TAG('S','C','N',' ')},*/ /* Sicilian */ +/*{HB_TAG('s','c','o',' '), HB_TAG('S','C','O',' ')},*/ /* Scots */ + {HB_TAG('s','c','s',' '), HB_TAG('S','C','S',' ')}, /* North Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ + {HB_TAG('s','d','c',' '), HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ + {HB_TAG('s','d','h',' '), HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ + {HB_TAG('s','d','n',' '), HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ + {HB_TAG('s','d','s',' '), HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ + {HB_TAG('s','e','h',' '), HB_TAG('S','N','A',' ')}, /* Sena */ + {HB_TAG('s','e','k',' '), HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ +/*{HB_TAG('s','e','l',' '), HB_TAG('S','E','L',' ')},*/ /* Selkup */ + {HB_TAG('s','e','z',' '), HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ + {HB_TAG('s','f','m',' '), HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ + {HB_TAG('s','f','m',' '), HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ +/*{HB_TAG('s','g','a',' '), HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ + {HB_TAG('s','g','c',' '), HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ + {HB_TAG('s','g','o',' '), HB_TAG_NONE }, /* Songa (retired code) != Sango */ +/*{HB_TAG('s','g','s',' '), HB_TAG('S','G','S',' ')},*/ /* Samogitian */ + {HB_TAG('s','g','w',' '), HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ + {HB_TAG('s','h','i',' '), HB_TAG('S','H','I',' ')}, /* Tachelhit */ + {HB_TAG('s','h','i',' '), HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ + {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ +/*{HB_TAG('s','h','n',' '), HB_TAG('S','H','N',' ')},*/ /* Shan */ + {HB_TAG('s','h','u',' '), HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ + {HB_TAG('s','h','y',' '), HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ + {HB_TAG('s','i','b',' '), HB_TAG_NONE }, /* Sebop != Sibe */ +/*{HB_TAG('s','i','d',' '), HB_TAG('S','I','D',' ')},*/ /* Sidamo */ + {HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */ + {HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ + {HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */ + {HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ + {HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ + {HB_TAG('s','k','g',' '), HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ + {HB_TAG('s','k','r',' '), HB_TAG('S','R','K',' ')}, /* Saraiki */ + {HB_TAG('s','k','s',' '), HB_TAG_NONE }, /* Maia != Skolt Sami */ + {HB_TAG('s','k','w',' '), HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ + {HB_TAG('s','k','y',' '), HB_TAG_NONE }, /* Sikaiana != Slovak */ + {HB_TAG('s','l','a',' '), HB_TAG_NONE }, /* Slavic [collection] != Slavey */ + {HB_TAG('s','m','a',' '), HB_TAG('S','S','M',' ')}, /* Southern Sami */ + {HB_TAG('s','m','d',' '), HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ + {HB_TAG('s','m','j',' '), HB_TAG('L','S','M',' ')}, /* Lule Sami */ + {HB_TAG('s','m','l',' '), HB_TAG_NONE }, /* Central Sama != Somali */ + {HB_TAG('s','m','n',' '), HB_TAG('I','S','M',' ')}, /* Inari Sami */ + {HB_TAG('s','m','s',' '), HB_TAG('S','K','S',' ')}, /* Skolt Sami */ + {HB_TAG('s','m','t',' '), HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ + {HB_TAG('s','n','b',' '), HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ + {HB_TAG('s','n','h',' '), HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ +/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */ + {HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ +/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */ + {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ + {HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ + {HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */ + {HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ + {HB_TAG('s','r','k',' '), HB_TAG_NONE }, /* Serudung Murut != Saraiki */ + {HB_TAG('s','r','m',' '), HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ + {HB_TAG('s','r','n',' '), HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ + {HB_TAG('s','r','o',' '), HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ +/*{HB_TAG('s','r','r',' '), HB_TAG('S','R','R',' ')},*/ /* Serer */ + {HB_TAG('s','r','s',' '), HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ + {HB_TAG('s','s','h',' '), HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ + {HB_TAG('s','s','l',' '), HB_TAG_NONE }, /* Western Sisaala != South Slavey */ + {HB_TAG('s','s','m',' '), HB_TAG_NONE }, /* Semnam != Southern Sami */ + {HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ +/*{HB_TAG('s','t','q',' '), HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ + {HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ +/*{HB_TAG('s','u','k',' '), HB_TAG('S','U','K',' ')},*/ /* Sukuma */ + {HB_TAG('s','u','q',' '), HB_TAG('S','U','R',' ')}, /* Suri */ + {HB_TAG('s','u','r',' '), HB_TAG_NONE }, /* Mwaghavul != Suri */ +/*{HB_TAG('s','v','a',' '), HB_TAG('S','V','A',' ')},*/ /* Svan */ + {HB_TAG('s','v','c',' '), HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ + {HB_TAG('s','v','e',' '), HB_TAG_NONE }, /* Serili != Swedish */ + {HB_TAG('s','w','b',' '), HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ + {HB_TAG('s','w','c',' '), HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ + {HB_TAG('s','w','h',' '), HB_TAG('S','W','K',' ')}, /* Swahili */ + {HB_TAG('s','w','k',' '), HB_TAG_NONE }, /* Malawi Sena != Swahili */ + {HB_TAG('s','w','n',' '), HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ + {HB_TAG('s','w','v',' '), HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ +/*{HB_TAG('s','x','u',' '), HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ + {HB_TAG('s','y','c',' '), HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ +/*{HB_TAG('s','y','l',' '), HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ +/*{HB_TAG('s','y','r',' '), HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ +/*{HB_TAG('s','z','l',' '), HB_TAG('S','Z','L',' ')},*/ /* Silesian */ + {HB_TAG('t','a','a',' '), HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ +/*{HB_TAG('t','a','b',' '), HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ + {HB_TAG('t','a','j',' '), HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ + {HB_TAG('t','a','q',' '), HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ + {HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ + {HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ + {HB_TAG('t','a','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ + {HB_TAG('t','c','b',' '), HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ + {HB_TAG('t','c','e',' '), HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ + {HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ + {HB_TAG('t','c','p',' '), HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ + {HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ + {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ + {HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ +/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ + {HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {HB_TAG('t','e','c',' '), HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ + {HB_TAG('t','e','m',' '), HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ +/*{HB_TAG('t','e','t',' '), HB_TAG('T','E','T',' ')},*/ /* Tetum */ + {HB_TAG('t','e','z',' '), HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ + {HB_TAG('t','f','n',' '), HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ + {HB_TAG('t','g','h',' '), HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ + {HB_TAG('t','g','j',' '), HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ + {HB_TAG('t','g','n',' '), HB_TAG_NONE }, /* Tandaganon != Tongan */ + {HB_TAG('t','g','r',' '), HB_TAG_NONE }, /* Tareng != Tigre */ + {HB_TAG('t','g','x',' '), HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ + {HB_TAG('t','g','y',' '), HB_TAG_NONE }, /* Togoyo != Tigrinya */ + {HB_TAG('t','h','t',' '), HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ + {HB_TAG('t','h','v',' '), HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ + {HB_TAG('t','h','v',' '), HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ + {HB_TAG('t','h','z',' '), HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ + {HB_TAG('t','h','z',' '), HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ + {HB_TAG('t','i','a',' '), HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ + {HB_TAG('t','i','g',' '), HB_TAG('T','G','R',' ')}, /* Tigre */ +/*{HB_TAG('t','i','v',' '), HB_TAG('T','I','V',' ')},*/ /* Tiv */ +/*{HB_TAG('t','j','l',' '), HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ + {HB_TAG('t','j','o',' '), HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ + {HB_TAG('t','k','g',' '), HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ + {HB_TAG('t','k','m',' '), HB_TAG_NONE }, /* Takelma != Turkmen */ +/*{HB_TAG('t','l','i',' '), HB_TAG('T','L','I',' ')},*/ /* Tlingit */ + {HB_TAG('t','m','g',' '), HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ + {HB_TAG('t','m','h',' '), HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ + {HB_TAG('t','m','h',' '), HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ + {HB_TAG('t','m','n',' '), HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ + {HB_TAG('t','m','w',' '), HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ + {HB_TAG('t','n','a',' '), HB_TAG_NONE }, /* Tacana != Tswana */ + {HB_TAG('t','n','e',' '), HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ + {HB_TAG('t','n','f',' '), HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ + {HB_TAG('t','n','f',' '), HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ + {HB_TAG('t','n','g',' '), HB_TAG_NONE }, /* Tobanga != Tonga */ + {HB_TAG('t','o','d',' '), HB_TAG('T','O','D','0')}, /* Toma */ + {HB_TAG('t','o','i',' '), HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {HB_TAG('t','o','j',' '), HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ + {HB_TAG('t','o','l',' '), HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ + {HB_TAG('t','o','r',' '), HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ + {HB_TAG('t','p','i',' '), HB_TAG('T','P','I',' ')}, /* Tok Pisin */ + {HB_TAG('t','p','i',' '), HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ + {HB_TAG('t','r','f',' '), HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ + {HB_TAG('t','r','k',' '), HB_TAG_NONE }, /* Turkic [collection] != Turkish */ + {HB_TAG('t','r','u',' '), HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ + {HB_TAG('t','r','u',' '), HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ + {HB_TAG('t','s','g',' '), HB_TAG_NONE }, /* Tausug != Tsonga */ +/*{HB_TAG('t','s','j',' '), HB_TAG('T','S','J',' ')},*/ /* Tshangla */ + {HB_TAG('t','t','c',' '), HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ + {HB_TAG('t','t','m',' '), HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ + {HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ + {HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ + {HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ + {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tumbuka */ +/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ + {HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ + {HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */ + {HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ +/*{HB_TAG('t','v','l',' '), HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ + {HB_TAG('t','v','y',' '), HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ + {HB_TAG('t','x','c',' '), HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ + {HB_TAG('t','x','y',' '), HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ + {HB_TAG('t','y','v',' '), HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ +/*{HB_TAG('t','y','z',' '), HB_TAG('T','Y','Z',' ')},*/ /* Tày */ + {HB_TAG('t','z','h',' '), HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ + {HB_TAG('t','z','j',' '), HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ + {HB_TAG('t','z','m',' '), HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ + {HB_TAG('t','z','m',' '), HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ + {HB_TAG('t','z','o',' '), HB_TAG('T','Z','O',' ')}, /* Tzotzil */ + {HB_TAG('t','z','o',' '), HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ + {HB_TAG('u','b','l',' '), HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ +/*{HB_TAG('u','d','m',' '), HB_TAG('U','D','M',' ')},*/ /* Udmurt */ + {HB_TAG('u','k','i',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) */ + {HB_TAG('u','l','n',' '), HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ +/*{HB_TAG('u','m','b',' '), HB_TAG('U','M','B',' ')},*/ /* Umbundu */ + {HB_TAG('u','n','r',' '), HB_TAG('M','U','N',' ')}, /* Mundari */ + {HB_TAG('u','r','k',' '), HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ + {HB_TAG('u','s','p',' '), HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ + {HB_TAG('u','z','n',' '), HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ + {HB_TAG('u','z','s',' '), HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ + {HB_TAG('v','a','p',' '), HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ +/*{HB_TAG('v','e','c',' '), HB_TAG('V','E','C',' ')},*/ /* Venetian */ + {HB_TAG('v','i','c',' '), HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ + {HB_TAG('v','i','t',' '), HB_TAG_NONE }, /* Viti != Vietnamese */ + {HB_TAG('v','k','k',' '), HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ + {HB_TAG('v','k','p',' '), HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ + {HB_TAG('v','k','t',' '), HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ + {HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ + {HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */ +/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */ + {HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */ +/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ + {HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */ + {HB_TAG('w','b','r',' '), HB_TAG('W','A','G',' ')}, /* Wagdi */ + {HB_TAG('w','b','r',' '), HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ +/*{HB_TAG('w','c','i',' '), HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ + {HB_TAG('w','e','a',' '), HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ + {HB_TAG('w','e','s',' '), HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ + {HB_TAG('w','e','u',' '), HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ + {HB_TAG('w','l','c',' '), HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ + {HB_TAG('w','l','e',' '), HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ + {HB_TAG('w','l','k',' '), HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ + {HB_TAG('w','n','i',' '), HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ + {HB_TAG('w','r','y',' '), HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ + {HB_TAG('w','s','g',' '), HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ +/*{HB_TAG('w','t','m',' '), HB_TAG('W','T','M',' ')},*/ /* Mewati */ + {HB_TAG('w','u','u',' '), HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ + {HB_TAG('x','a','l',' '), HB_TAG('K','L','M',' ')}, /* Kalmyk */ + {HB_TAG('x','a','l',' '), HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ + {HB_TAG('x','a','n',' '), HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ + {HB_TAG('x','b','d',' '), HB_TAG_NONE }, /* Bindal != Lü */ +/*{HB_TAG('x','j','b',' '), HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ +/*{HB_TAG('x','k','f',' '), HB_TAG('X','K','F',' ')},*/ /* Khengkha */ + {HB_TAG('x','m','g',' '), HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ + {HB_TAG('x','m','m',' '), HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ + {HB_TAG('x','m','m',' '), HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ + {HB_TAG('x','m','v',' '), HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ + {HB_TAG('x','m','w',' '), HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ + {HB_TAG('x','n','j',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ + {HB_TAG('x','n','q',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ + {HB_TAG('x','n','r',' '), HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ +/*{HB_TAG('x','o','g',' '), HB_TAG('X','O','G',' ')},*/ /* Soga */ + {HB_TAG('x','p','e',' '), HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {HB_TAG('x','p','e',' '), HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ + {HB_TAG('x','s','l',' '), HB_TAG('S','S','L',' ')}, /* South Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ + {HB_TAG('x','s','t',' '), HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ +/*{HB_TAG('x','u','b',' '), HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ +/*{HB_TAG('x','u','j',' '), HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ + {HB_TAG('x','u','p',' '), HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ + {HB_TAG('x','w','o',' '), HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ + {HB_TAG('y','a','j',' '), HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ + {HB_TAG('y','a','k',' '), HB_TAG_NONE }, /* Yakama != Sakha */ +/*{HB_TAG('y','a','o',' '), HB_TAG('Y','A','O',' ')},*/ /* Yao */ +/*{HB_TAG('y','a','p',' '), HB_TAG('Y','A','P',' ')},*/ /* Yapese */ + {HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */ + {HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ + {HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ + {HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ +/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */ + {HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ + {HB_TAG('y','i','m',' '), HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ +/*{HB_TAG('y','n','a',' '), HB_TAG('Y','N','A',' ')},*/ /* Aluo */ + {HB_TAG('y','o','s',' '), HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ + {HB_TAG('y','u','a',' '), HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ + {HB_TAG('y','u','e',' '), HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ +/*{HB_TAG('y','w','q',' '), HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ + {HB_TAG('z','c','h',' '), HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','d','j',' '), HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ +/*{HB_TAG('z','e','a',' '), HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ + {HB_TAG('z','e','h',' '), HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','e','n',' '), HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ + {HB_TAG('z','g','b',' '), HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ + {HB_TAG('z','g','h',' '), HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ + {HB_TAG('z','g','h',' '), HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ + {HB_TAG('z','g','m',' '), HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ + {HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ + {HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ + {HB_TAG('z','h','n',' '), HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ + {HB_TAG('z','l','j',' '), HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ + {HB_TAG('z','l','m',' '), HB_TAG('M','L','Y',' ')}, /* Malay */ + {HB_TAG('z','l','n',' '), HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ + {HB_TAG('z','l','q',' '), HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ + {HB_TAG('z','m','i',' '), HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ + {HB_TAG('z','m','z',' '), HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ + {HB_TAG('z','n','d',' '), HB_TAG_NONE }, /* Zande [collection] != Zande */ + {HB_TAG('z','n','e',' '), HB_TAG('Z','N','D',' ')}, /* Zande */ + {HB_TAG('z','o','m',' '), HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ + {HB_TAG('z','q','e',' '), HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ + {HB_TAG('z','s','m',' '), HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ + {HB_TAG('z','u','m',' '), HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ + {HB_TAG('z','y','b',' '), HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ + {HB_TAG('z','y','g',' '), HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ + {HB_TAG('z','y','j',' '), HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ + {HB_TAG('z','y','n',' '), HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ + {HB_TAG('z','y','p',' '), HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ +/*{HB_TAG('z','z','a',' '), HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ + {HB_TAG('z','z','j',' '), HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ }; /** @@ -1629,69 +1642,75 @@ hb_ot_tags_from_complex_language (const char *lang_str, unsigned int *count /* IN/OUT */, hb_tag_t *tags /* OUT */) { - if (subtag_matches (lang_str, limit, "-fonnapa")) - { - /* Undetermined; North American Phonetic Alphabet */ - tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-polyton")) - { - /* Modern Greek (1453-); Polytonic Greek */ - tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-arevmda")) - { - /* Armenian; Western Armenian (retired code) */ - tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-provenc")) - { - /* Occitan (post 1500); Provençal */ - tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-fonipa")) - { - /* Undetermined; International Phonetic Alphabet */ - tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-geok")) - { - /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ - tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syre")) - { - /* Undetermined; Syriac (Estrangelo variant) */ - tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrj")) - { - /* Undetermined; Syriac (Western variant) */ - tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrn")) + if (limit - lang_str >= 7) { - /* Undetermined; Syriac (Eastern variant) */ - tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ - *count = 1; - return true; + const char *p = strchr (lang_str, '-'); + if (!p || p >= limit || limit - p < 5) goto out; + if (subtag_matches (p, limit, "-fonnapa", 8)) + { + /* Undetermined; North American Phonetic Alphabet */ + tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-polyton", 8)) + { + /* Modern Greek (1453-); Polytonic Greek */ + tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-arevmda", 8)) + { + /* Armenian; Western Armenian (retired code) */ + tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-provenc", 8)) + { + /* Occitan (post 1500); Provençal */ + tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-fonipa", 7)) + { + /* Undetermined; International Phonetic Alphabet */ + tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-geok", 5)) + { + /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syre", 5)) + { + /* Undetermined; Syriac (Estrangelo variant) */ + tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrj", 5)) + { + /* Undetermined; Syriac (Western variant) */ + tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrn", 5)) + { + /* Undetermined; Syriac (Eastern variant) */ + tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + *count = 1; + return true; + } } +out: switch (lang_str[0]) { case 'a': @@ -1704,14 +1723,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'c': - if (lang_matches (&lang_str[1], "do-hant-hk")) + if (lang_matches (&lang_str[1], limit, "do-hant-hk", 10)) { /* Min Dong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant-mo")) + if (lang_matches (&lang_str[1], limit, "do-hant-mo", 10)) { /* Min Dong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1724,14 +1743,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "jy-hant-hk")) + if (lang_matches (&lang_str[1], limit, "jy-hant-hk", 10)) { /* Jinyu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant-mo")) + if (lang_matches (&lang_str[1], limit, "jy-hant-mo", 10)) { /* Jinyu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1744,14 +1763,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "mn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "mn-hant-hk", 10)) { /* Mandarin Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "mn-hant-mo", 10)) { /* Mandarin Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1764,14 +1783,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1784,14 +1803,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "px-hant-hk")) + if (lang_matches (&lang_str[1], limit, "px-hant-hk", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant-mo")) + if (lang_matches (&lang_str[1], limit, "px-hant-mo", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1804,14 +1823,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sp-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sp-hant-hk", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sp-hant-mo", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1824,14 +1843,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zh-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zh-hant-hk", 10)) { /* Huizhou Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zh-hant-mo", 10)) { /* Huizhou Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1844,14 +1863,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zo-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zo-hant-hk", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zo-hant-mo", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1864,112 +1883,112 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "do-hans")) + if (lang_matches (&lang_str[1], limit, "do-hans", 7)) { /* Min Dong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant")) + if (lang_matches (&lang_str[1], limit, "do-hant", 7)) { /* Min Dong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hans")) + if (lang_matches (&lang_str[1], limit, "jy-hans", 7)) { /* Jinyu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant")) + if (lang_matches (&lang_str[1], limit, "jy-hant", 7)) { /* Jinyu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hans")) + if (lang_matches (&lang_str[1], limit, "mn-hans", 7)) { /* Mandarin Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant")) + if (lang_matches (&lang_str[1], limit, "mn-hant", 7)) { /* Mandarin Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Northern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Northern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hans")) + if (lang_matches (&lang_str[1], limit, "px-hans", 7)) { /* Pu-Xian Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant")) + if (lang_matches (&lang_str[1], limit, "px-hant", 7)) { /* Pu-Xian Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hans")) + if (lang_matches (&lang_str[1], limit, "sp-hans", 7)) { /* Southern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant")) + if (lang_matches (&lang_str[1], limit, "sp-hant", 7)) { /* Southern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Huizhou Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant")) + if (lang_matches (&lang_str[1], limit, "zh-hant", 7)) { /* Huizhou Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hans")) + if (lang_matches (&lang_str[1], limit, "zo-hans", 7)) { /* Min Zhong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant")) + if (lang_matches (&lang_str[1], limit, "zo-hant", 7)) { /* Min Zhong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -1977,7 +1996,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Dong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -1985,7 +2004,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Dong Chinese; Macao */ unsigned int i; @@ -1999,7 +2018,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Dong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2007,7 +2026,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Jinyu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2015,7 +2034,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Jinyu Chinese; Macao */ unsigned int i; @@ -2029,7 +2048,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Jinyu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2037,7 +2056,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Mandarin Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2045,7 +2064,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Mandarin Chinese; Macao */ unsigned int i; @@ -2059,7 +2078,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Mandarin Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2067,7 +2086,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Northern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2075,7 +2094,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Northern Ping Chinese; Macao */ unsigned int i; @@ -2089,7 +2108,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Northern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2097,7 +2116,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Pu-Xian Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2105,7 +2124,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Pu-Xian Chinese; Macao */ unsigned int i; @@ -2119,7 +2138,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Pu-Xian Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2127,7 +2146,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Southern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2135,7 +2154,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Southern Ping Chinese; Macao */ unsigned int i; @@ -2149,7 +2168,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Southern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2157,7 +2176,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Huizhou Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2165,7 +2184,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Huizhou Chinese; Macao */ unsigned int i; @@ -2179,7 +2198,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Huizhou Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2187,7 +2206,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Zhong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2195,7 +2214,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Zhong Chinese; Macao */ unsigned int i; @@ -2209,7 +2228,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Zhong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2218,14 +2237,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'g': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Gan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Gan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2238,21 +2257,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Gan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Gan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "a-latg")) + if (lang_matches (&lang_str[1], limit, "a-latg", 6)) { /* Irish; Latin (Gaelic variant) */ tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ @@ -2260,7 +2279,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Gan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2268,7 +2287,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Gan Chinese; Macao */ unsigned int i; @@ -2282,7 +2301,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Gan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2291,14 +2310,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'h': - if (lang_matches (&lang_str[1], "ak-hant-hk")) + if (lang_matches (&lang_str[1], limit, "ak-hant-hk", 10)) { /* Hakka Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant-mo")) + if (lang_matches (&lang_str[1], limit, "ak-hant-mo", 10)) { /* Hakka Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2311,14 +2330,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10)) { /* Xiang Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sn-hant-mo", 10)) { /* Xiang Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2331,28 +2350,28 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "ak-hans")) + if (lang_matches (&lang_str[1], limit, "ak-hans", 7)) { /* Hakka Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant")) + if (lang_matches (&lang_str[1], limit, "ak-hant", 7)) { /* Hakka Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hans")) + if (lang_matches (&lang_str[1], limit, "sn-hans", 7)) { /* Xiang Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant")) + if (lang_matches (&lang_str[1], limit, "sn-hant", 7)) { /* Xiang Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2360,7 +2379,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Hakka Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2368,7 +2387,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Hakka Chinese; Macao */ unsigned int i; @@ -2382,7 +2401,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Hakka Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2390,7 +2409,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Xiang Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2398,7 +2417,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Xiang Chinese; Macao */ unsigned int i; @@ -2412,7 +2431,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Xiang Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2450,7 +2469,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'l': - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Literary Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2459,14 +2478,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'm': - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Min Bei Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Min Bei Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2479,14 +2498,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Min Bei Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Min Bei Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2494,7 +2513,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Bei Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2502,7 +2521,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Bei Chinese; Macao */ unsigned int i; @@ -2516,7 +2535,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Bei Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2524,7 +2543,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "nw-", 3) - && subtag_matches (lang_str, limit, "-th")) + && subtag_matches (lang_str, limit, "-th", 3)) { /* Mon; Thailand */ tags[0] = HB_TAG('M','O','N','T'); /* Thailand Mon */ @@ -2533,14 +2552,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'n': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Min Nan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Min Nan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2553,14 +2572,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Min Nan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Min Nan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2568,7 +2587,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Nan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2576,7 +2595,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Nan Chinese; Macao */ unsigned int i; @@ -2590,7 +2609,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Nan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2607,36 +2626,36 @@ hb_ot_tags_from_complex_language (const char *lang_str, if (0 == strcmp (&lang_str[1], "o-nyn")) { /* Norwegian Nynorsk (retired code) */ - unsigned int i; - hb_tag_t possible_tags[] = { - HB_TAG('N','Y','N',' '), /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - HB_TAG('N','O','R',' '), /* Norwegian */ - }; - for (i = 0; i < 2 && i < *count; i++) - tags[i] = possible_tags[i]; - *count = i; + tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + *count = 1; return true; } break; case 'r': if (0 == strncmp (&lang_str[1], "o-", 2) - && subtag_matches (lang_str, limit, "-md")) + && subtag_matches (lang_str, limit, "-md", 3)) { /* Romanian; Moldova */ - tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('M','O','L',' '), /* Moldavian */ + HB_TAG('R','O','M',' '), /* Romanian */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } break; case 'w': - if (lang_matches (&lang_str[1], "uu-hant-hk")) + if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10)) { /* Wu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant-mo")) + if (lang_matches (&lang_str[1], limit, "uu-hant-mo", 10)) { /* Wu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2649,14 +2668,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "uu-hans")) + if (lang_matches (&lang_str[1], limit, "uu-hans", 7)) { /* Wu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant")) + if (lang_matches (&lang_str[1], limit, "uu-hant", 7)) { /* Wu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2664,7 +2683,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Wu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2672,7 +2691,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Wu Chinese; Macao */ unsigned int i; @@ -2686,7 +2705,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Wu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2695,7 +2714,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'y': - if (lang_matches (&lang_str[1], "ue-hans")) + if (lang_matches (&lang_str[1], limit, "ue-hans", 7)) { /* Yue Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2704,14 +2723,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'z': - if (lang_matches (&lang_str[1], "h-hant-hk")) + if (lang_matches (&lang_str[1], limit, "h-hant-hk", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant-mo")) + if (lang_matches (&lang_str[1], limit, "h-hant-mo", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Macao */ unsigned int i; @@ -2731,14 +2750,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hans")) + if (lang_matches (&lang_str[1], limit, "h-hans", 6)) { /* Chinese [macrolanguage]; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant")) + if (lang_matches (&lang_str[1], limit, "h-hant", 6)) { /* Chinese [macrolanguage]; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2753,7 +2772,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Chinese [macrolanguage]; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2761,7 +2780,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Chinese [macrolanguage]; Macao */ unsigned int i; @@ -2775,7 +2794,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Chinese [macrolanguage]; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2813,15 +2832,15 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('A','R','K',' '): /* Rakhine */ return hb_language_from_string ("rki", -1); /* Rakhine */ case HB_TAG('A','T','H',' '): /* Athapaskan */ - return hb_language_from_string ("ath", -1); /* Athapascan [family] */ + return hb_language_from_string ("ath", -1); /* Athapascan [collection] */ case HB_TAG('B','B','R',' '): /* Berber */ - return hb_language_from_string ("ber", -1); /* Berber [family] */ + return hb_language_from_string ("ber", -1); /* Berber [collection] */ case HB_TAG('B','I','K',' '): /* Bikol */ return hb_language_from_string ("bik", -1); /* Bikol [macrolanguage] */ case HB_TAG('B','T','K',' '): /* Batak */ - return hb_language_from_string ("btk", -1); /* Batak [family] */ + return hb_language_from_string ("btk", -1); /* Batak [collection] */ case HB_TAG('C','P','P',' '): /* Creoles */ - return hb_language_from_string ("crp", -1); /* Creoles and pidgins [family] */ + return hb_language_from_string ("crp", -1); /* Creoles and pidgins [collection] */ case HB_TAG('C','R','R',' '): /* Carrier */ return hb_language_from_string ("crx", -1); /* Carrier */ case HB_TAG('D','G','R',' '): /* Dogri (macrolanguage) */ @@ -2838,6 +2857,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */ case HB_TAG('G','O','N',' '): /* Gondi */ return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */ + case HB_TAG('H','M','A',' '): /* High Mari */ + return hb_language_from_string ("mrj", -1); /* Western Mari */ case HB_TAG('H','M','N',' '): /* Hmong */ return hb_language_from_string ("hmn", -1); /* Hmong [macrolanguage] */ case HB_TAG('H','N','D',' '): /* Hindko */ @@ -2847,7 +2868,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('I','B','A',' '): /* Iban */ return hb_language_from_string ("iba", -1); /* Iban */ case HB_TAG('I','J','O',' '): /* Ijo */ - return hb_language_from_string ("ijo", -1); /* Ijo [family] */ + 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 */ @@ -2873,11 +2894,13 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('K','P','L',' '): /* Kpelle */ return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */ case HB_TAG('K','R','N',' '): /* Karen */ - return hb_language_from_string ("kar", -1); /* Karen [family] */ + return hb_language_from_string ("kar", -1); /* Karen [collection] */ case HB_TAG('K','U','I',' '): /* Kui */ 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 */ + return hb_language_from_string ("mhr", -1); /* Eastern Mari */ case HB_TAG('L','U','H',' '): /* Luyia */ return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */ case HB_TAG('L','V','I',' '): /* Latvian */ @@ -2897,9 +2920,9 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('M','O','N','T'): /* Thailand Mon */ return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */ case HB_TAG('M','Y','N',' '): /* Mayan */ - return hb_language_from_string ("myn", -1); /* Mayan [family] */ + return hb_language_from_string ("myn", -1); /* Mayan [collection] */ case HB_TAG('N','A','H',' '): /* Nahuatl */ - return hb_language_from_string ("nah", -1); /* Nahuatl [family] */ + 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 */ @@ -2926,6 +2949,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */ case HB_TAG('R','A','J',' '): /* Rajasthani */ return hb_language_from_string ("raj", -1); /* Rajasthani [macrolanguage] */ + case HB_TAG('R','O','M',' '): /* Romanian */ + return hb_language_from_string ("ro", -1); /* Romanian */ case HB_TAG('R','O','Y',' '): /* Romany */ return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */ case HB_TAG('S','Q','I',' '): /* Albanian */ diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc index 1837063af8..a4a9515362 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag.cc +++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc @@ -41,6 +41,7 @@ hb_ot_old_tag_from_script (hb_script_t script) switch ((hb_tag_t) script) { case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; + case HB_SCRIPT_MATH: return HB_OT_TAG_MATH_SCRIPT; /* KATAKANA and HIRAGANA both map to 'kana' */ case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a'); @@ -63,6 +64,8 @@ hb_ot_old_tag_to_script (hb_tag_t tag) { if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT)) return HB_SCRIPT_INVALID; + if (unlikely (tag == HB_OT_TAG_MATH_SCRIPT)) + return HB_SCRIPT_MATH; /* This side of the conversion is fully algorithmic. */ @@ -186,48 +189,46 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -static bool +static inline bool subtag_matches (const char *lang_str, const char *limit, - const char *subtag) + const char *subtag, + unsigned subtag_len) { + if (likely ((unsigned) (limit - lang_str) < subtag_len)) + return false; + do { const char *s = strstr (lang_str, subtag); if (!s || s >= limit) return false; - if (!ISALNUM (s[strlen (subtag)])) + if (!ISALNUM (s[subtag_len])) return true; - lang_str = s + strlen (subtag); + lang_str = s + subtag_len; } while (true); } -static hb_bool_t -lang_matches (const char *lang_str, const char *spec) +static bool +lang_matches (const char *lang_str, + const char *limit, + const char *spec, + unsigned spec_len) { - unsigned int len = strlen (spec); + if (likely ((unsigned) (limit - lang_str) < spec_len)) + return false; - return strncmp (lang_str, spec, len) == 0 && - (lang_str[len] == '\0' || lang_str[len] == '-'); + return strncmp (lang_str, spec, spec_len) == 0 && + (lang_str[spec_len] == '\0' || lang_str[spec_len] == '-'); } struct LangTag { - char language[4]; + hb_tag_t language; hb_tag_t tag; - int cmp (const char *a) const + int cmp (hb_tag_t a) const { - const char *b = this->language; - unsigned int da, db; - const char *p; - - p = strchr (a, '-'); - da = p ? (unsigned int) (p - a) : strlen (a); - - p = strchr (b, '-'); - db = p ? (unsigned int) (p - b) : strlen (b); - - return strncmp (a, b, hb_max (da, db)); + return a < this->language ? -1 : a > this->language ? +1 : 0; } int cmp (const LangTag *that) const { return cmp (that->language); } @@ -263,7 +264,6 @@ hb_ot_tags_from_language (const char *lang_str, hb_tag_t *tags) { const char *s; - unsigned int tag_idx; /* Check for matches of multiple subtags. */ if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) @@ -280,17 +280,39 @@ hb_ot_tags_from_language (const char *lang_str, ISALPHA (s[1])) lang_str = s + 1; } - if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx)) + const LangTag *ot_languages = nullptr; + unsigned ot_languages_len = 0; + const char *dash = strchr (lang_str, '-'); + unsigned first_len = dash ? dash - lang_str : limit - lang_str; + if (first_len == 2) { + ot_languages = ot_languages2; + ot_languages_len = ARRAY_LENGTH (ot_languages2); + } + else if (first_len == 3) + { + ot_languages = ot_languages3; + ot_languages_len = ARRAY_LENGTH (ot_languages3); + } + + hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); + + static unsigned last_tag_idx; /* Poor man's cache. */ + unsigned tag_idx = last_tag_idx; + + if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx)) + { + last_tag_idx = tag_idx; unsigned int i; while (tag_idx != 0 && - 0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language)) + ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language) tag_idx--; for (i = 0; i < *count && - tag_idx + i < ARRAY_LENGTH (ot_languages) && + tag_idx + i < ot_languages_len && ot_languages[tag_idx + i].tag != HB_TAG_NONE && - 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language); + ot_languages[tag_idx + i].language == ot_languages[tag_idx].language; i++) tags[i] = ot_languages[tag_idx + i].tag; *count = i; @@ -456,9 +478,19 @@ hb_ot_tag_to_language (hb_tag_t tag) return disambiguated_tag; } - for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tag == tag) - return hb_language_from_string (ot_languages[i].language, -1); + char buf[4]; + for (i = 0; i < ARRAY_LENGTH (ot_languages2); i++) + if (ot_languages2[i].tag == tag) + { + hb_tag_to_string (ot_languages2[i].language, buf); + return hb_language_from_string (buf, 2); + } + for (i = 0; i < ARRAY_LENGTH (ot_languages3); i++) + if (ot_languages3[i].tag == tag) + { + hb_tag_to_string (ot_languages3[i].language, buf); + return hb_language_from_string (buf, 3); + } /* Return a custom language in the form of "x-hbot-AABBCCDD". * If it's three letters long, also guess it's ISO 639-3 and lower-case and @@ -554,13 +586,23 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, static inline void test_langs_sorted () { - for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++) + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages2); i++) + { + int c = ot_languages2[i].cmp (&ot_languages2[i - 1]); + if (c > 0) + { + fprintf (stderr, "ot_languages2 not sorted at index %d: %08x %d %08x\n", + i, ot_languages2[i-1].language, c, ot_languages2[i].language); + abort(); + } + } + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++) { - int c = ot_languages[i].cmp (&ot_languages[i - 1]); + int c = ot_languages3[i].cmp (&ot_languages3[i - 1]); if (c > 0) { - fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n", - i, ot_languages[i-1].language, c, ot_languages[i].language); + fprintf (stderr, "ot_languages3 not sorted at index %d: %08x %d %08x\n", + i, ot_languages3[i-1].language, c, ot_languages3[i].language); abort(); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh index 05f289db26..e066558683 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh @@ -263,7 +263,7 @@ struct fvar if (coords_length && *coords_length) { hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount) - .sub_array (0, *coords_length); + .sub_array (0, coords_length); for (unsigned int i = 0; i < instanceCoords.length; i++) coords[i] = instanceCoords.arrayZ[i].to_float (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh index 49b5532d40..3b2a38b9a6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh @@ -390,16 +390,13 @@ struct gvar { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && (version.major == 1) && - (glyphCount == c->get_num_glyphs ()) && sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && (is_long_offset () ? c->check_array (get_long_offset_array (), glyphCount+1) : - c->check_array (get_short_offset_array (), glyphCount+1)) && - c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0), - get_offset (glyphCount) - get_offset (0))); + c->check_array (get_short_offset_array (), glyphCount+1))); } - /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */ + /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ bool sanitize (hb_sanitize_context_t *c) const { return sanitize_shallow (c); } @@ -482,7 +479,9 @@ struct gvar const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const { unsigned start_offset = get_offset (glyph); - unsigned length = get_offset (glyph+1) - start_offset; + unsigned end_offset = get_offset (glyph+1); + if (unlikely (end_offset < start_offset)) return hb_bytes_t (); + unsigned length = end_offset - start_offset; hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); } @@ -490,7 +489,10 @@ struct gvar bool is_long_offset () const { return flags & 1; } unsigned get_offset (unsigned i) const - { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } + { + if (unlikely (i > glyphCount)) return 0; + return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; + } const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; } const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; } @@ -498,9 +500,9 @@ struct gvar public: struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<gvar> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } private: struct x_getter { static float get (const contour_point_t &p) { return p.x; } }; @@ -577,10 +579,11 @@ struct gvar hb_bytes_t bytes ((const char *) p, length); hb_vector_t<unsigned int> private_indices; - if (iterator.current_tuple->has_private_points () && + bool has_private_points = iterator.current_tuple->has_private_points (); + if (has_private_points && !GlyphVariationData::unpack_points (p, private_indices, bytes)) return false; - const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices; + const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices; bool apply_to_all = (indices.length == 0); unsigned int num_deltas = apply_to_all ? points.length : indices.length; @@ -695,10 +698,12 @@ no_more_gaps: offsetZ; /* Offsets from the start of the GlyphVariationData array * to each GlyphVariationData table. */ public: - DEFINE_SIZE_MIN (20); + DEFINE_SIZE_ARRAY (20, offsetZ); }; -struct gvar_accelerator_t : gvar::accelerator_t {}; +struct gvar_accelerator_t : gvar::accelerator_t { + gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh index 074b6a3785..e9d90352f0 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh @@ -177,9 +177,6 @@ struct hvarvvar_subset_plan_t inner_maps.resize (var_store->get_sub_table_count ()); - for (unsigned int i = 0; i < inner_maps.length; i++) - inner_maps[i].init (); - if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; bool retain_adv_map = false; @@ -229,8 +226,8 @@ struct hvarvvar_subset_plan_t for (unsigned int i = 0; i < inner_sets.length; i++) hb_set_destroy (inner_sets[i]); hb_set_destroy (adv_set); - inner_maps.fini_deep (); - index_map_plans.fini_deep (); + inner_maps.fini (); + index_map_plans.fini (); } hb_inc_bimap_t outer_map; diff --git a/thirdparty/harfbuzz/src/hb-ot-var.cc b/thirdparty/harfbuzz/src/hb-ot-var.cc index 6b42b45cd9..0376e26b4a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var.cc +++ b/thirdparty/harfbuzz/src/hb-ot-var.cc @@ -303,6 +303,9 @@ hb_ot_var_normalize_variations (hb_face_t *face, * values for the axis are mapped to the interval [-1,1], with the default * axis value mapped to 0. * + * The normalized values have 14 bits of fixed-point sub-integer precision as per + * OpenType specification. + * * Any additional scaling defined in the face's `avar` table is also * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar * diff --git a/thirdparty/harfbuzz/src/hb-ot-var.h b/thirdparty/harfbuzz/src/hb-ot-var.h index ce201d3b4f..05147cc25e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var.h +++ b/thirdparty/harfbuzz/src/hb-ot-var.h @@ -109,7 +109,7 @@ typedef enum { /*< flags >*/ * @tag: The #hb_tag_t tag identifying the design variation of the axis * @name_id: The `name` table Name ID that provides display names for the axis * @flags: The #hb_ot_var_axis_flags_t flags for the axis - * @min_value: The mininum value on the variation axis that the font covers + * @min_value: The minimum value on the variation axis that the font covers * @default_value: The position on the variation axis corresponding to the font's defaults * @max_value: The maximum value on the variation axis that the font covers * diff --git a/thirdparty/harfbuzz/src/hb-priority-queue.hh b/thirdparty/harfbuzz/src/hb-priority-queue.hh index 7d799ae906..ffb86e30ae 100644 --- a/thirdparty/harfbuzz/src/hb-priority-queue.hh +++ b/thirdparty/harfbuzz/src/hb-priority-queue.hh @@ -38,18 +38,11 @@ */ struct hb_priority_queue_t { - HB_DELETE_COPY_ASSIGN (hb_priority_queue_t); - hb_priority_queue_t () { init (); } - ~hb_priority_queue_t () { fini (); } - private: typedef hb_pair_t<int64_t, unsigned> item_t; hb_vector_t<item_t> heap; public: - void init () { heap.init (); } - - void fini () { heap.fini (); } void reset () { heap.resize (0); } @@ -58,14 +51,17 @@ struct hb_priority_queue_t void insert (int64_t priority, unsigned value) { heap.push (item_t (priority, value)); + if (unlikely (heap.in_error ())) return; bubble_up (heap.length - 1); } item_t pop_minimum () { - item_t result = heap[0]; + assert (!is_empty ()); + + item_t result = heap.arrayZ[0]; - heap[0] = heap[heap.length - 1]; + heap.arrayZ[0] = heap.arrayZ[heap.length - 1]; heap.shrink (heap.length - 1); bubble_down (0); @@ -104,6 +100,8 @@ struct hb_priority_queue_t void bubble_down (unsigned index) { + assert (index <= heap.length); + unsigned left = left_child (index); unsigned right = right_child (index); @@ -113,11 +111,11 @@ struct hb_priority_queue_t return; bool has_right = right < heap.length; - if (heap[index].first <= heap[left].first - && (!has_right || heap[index].first <= heap[right].first)) + if (heap.arrayZ[index].first <= heap.arrayZ[left].first + && (!has_right || heap[index].first <= heap.arrayZ[right].first)) return; - if (!has_right || heap[left].first < heap[right].first) + if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first) { swap (index, left); bubble_down (left); @@ -130,10 +128,12 @@ struct hb_priority_queue_t void bubble_up (unsigned index) { + assert (index <= heap.length); + if (index == 0) return; unsigned parent_index = parent (index); - if (heap[parent_index].first <= heap[index].first) + if (heap.arrayZ[parent_index].first <= heap.arrayZ[index].first) return; swap (index, parent_index); @@ -142,9 +142,9 @@ struct hb_priority_queue_t void swap (unsigned a, unsigned b) { - item_t temp = heap[a]; - heap[a] = heap[b]; - heap[b] = temp; + assert (a <= heap.length); + assert (b <= heap.length); + hb_swap (heap.arrayZ[a], heap.arrayZ[b]); } }; diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh index 5c46b4cccc..ce9ff90bb4 100644 --- a/thirdparty/harfbuzz/src/hb-repacker.hh +++ b/thirdparty/harfbuzz/src/hb-repacker.hh @@ -37,31 +37,28 @@ * For a detailed writeup on the overflow resolution algorithm see: * docs/repacker.md */ - struct graph_t { struct vertex_t { - vertex_t () : - distance (0), - space (0), - parents (), - start (0), - end (0), - priority(0) {} - - void fini () { - obj.fini (); - parents.fini (); - } - hb_serialize_context_t::object_t obj; - int64_t distance; - int64_t space; + int64_t distance = 0 ; + int64_t space = 0 ; hb_vector_t<unsigned> parents; - unsigned start; - unsigned end; - unsigned priority; + unsigned start = 0; + unsigned end = 0; + unsigned priority = 0; + + friend void swap (vertex_t& a, vertex_t& b) + { + hb_swap (a.obj, b.obj); + hb_swap (a.distance, b.distance); + hb_swap (a.space, b.space); + hb_swap (a.parents, b.parents); + hb_swap (a.start, b.start); + hb_swap (a.end, b.end); + hb_swap (a.priority, b.priority); + } bool is_shared () const { @@ -153,7 +150,8 @@ struct graph_t * the 'packed' object stack used internally in the * serializer */ - graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects) + template<typename T> + graph_t (const T& objects) : parents_invalid (true), distance_invalid (true), positions_invalid (true), @@ -161,6 +159,8 @@ struct graph_t { num_roots_for_space_.push (1); bool removed_nil = false; + vertices_.alloc (objects.length); + vertices_scratch_.alloc (objects.length); for (unsigned i = 0; i < objects.length; i++) { // TODO(grieger): check all links point to valid objects. @@ -186,7 +186,7 @@ struct graph_t ~graph_t () { - vertices_.fini_deep (); + vertices_.fini (); } bool in_error () const @@ -260,59 +260,6 @@ struct graph_t } /* - * Generates a new topological sorting of graph using Kahn's - * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms - */ - void sort_kahn () - { - positions_invalid = true; - - if (vertices_.length <= 1) { - // Graph of 1 or less doesn't need sorting. - return; - } - - hb_vector_t<unsigned> queue; - hb_vector_t<vertex_t> sorted_graph; - if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; - hb_vector_t<unsigned> id_map; - if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; - - hb_vector_t<unsigned> removed_edges; - if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; - update_parents (); - - queue.push (root_idx ()); - int new_id = vertices_.length - 1; - - while (!queue.in_error () && queue.length) - { - unsigned next_id = queue[0]; - queue.remove (0); - - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; - id_map[next_id] = new_id--; - - for (const auto& link : next.obj.all_links ()) { - removed_edges[link.objidx]++; - if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) - queue.push (link.objidx); - } - } - - check_success (!queue.in_error ()); - check_success (!sorted_graph.in_error ()); - if (!check_success (new_id == -1)) - print_orphaned_nodes (); - - remap_all_obj_indices (id_map, &sorted_graph); - - hb_swap (vertices_, sorted_graph); - sorted_graph.fini_deep (); - } - - /* * Generates a new topological sorting of graph ordered by the shortest * distance to each node. */ @@ -328,7 +275,7 @@ struct graph_t update_distances (); hb_priority_queue_t queue; - hb_vector_t<vertex_t> sorted_graph; + hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_; if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; hb_vector_t<unsigned> id_map; if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; @@ -344,8 +291,9 @@ struct graph_t { unsigned next_id = queue.pop_minimum().second; - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; + hb_swap (sorted_graph[new_id], vertices_[next_id]); + const vertex_t& next = sorted_graph[new_id]; + id_map[next_id] = new_id--; for (const auto& link : next.obj.all_links ()) { @@ -369,7 +317,6 @@ struct graph_t remap_all_obj_indices (id_map, &sorted_graph); hb_swap (vertices_, sorted_graph); - sorted_graph.fini_deep (); } /* @@ -402,11 +349,15 @@ struct graph_t while (roots) { unsigned next = HB_SET_VALUE_INVALID; + if (unlikely (!check_success (!roots.in_error ()))) break; if (!roots.next (&next)) break; hb_set_t connected_roots; find_connected_nodes (next, roots, visited, connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; + isolate_subgraph (connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; unsigned next_space = this->next_space (); num_roots_for_space_.push (0); @@ -423,6 +374,8 @@ struct graph_t // into the 32 bit space as needed, instead of using isolation. } + + return true; } @@ -575,12 +528,10 @@ struct graph_t // The last object is the root of the graph, so swap back the root to the end. // The root's obj idx does change, however since it's root nothing else refers to it. // all other obj idx's will be unaffected. - vertex_t root = vertices_[vertices_.length - 2]; - vertices_[clone_idx] = *clone; - vertices_[vertices_.length - 1] = root; + hb_swap (vertices_[vertices_.length - 2], *clone); // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root.obj.all_links ()) + for (const auto& l : root ().obj.all_links ()) vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); return clone_idx; @@ -865,7 +816,7 @@ struct graph_t // Redundant ones are filtered out later on by the visited set. // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf // for practical performance this is faster then using a more advanced queue - // (such as a fibonaacci queue) with a fast decrease priority. + // (such as a fibonacci queue) with a fast decrease priority. for (unsigned i = 0; i < vertices_.length; i++) { if (i == vertices_.length - 1) @@ -1074,6 +1025,7 @@ struct graph_t hb_set_t& visited, hb_set_t& connected) { + if (unlikely (!check_success (!visited.in_error ()))) return; if (visited.has (start_idx)) return; visited.add (start_idx); @@ -1096,6 +1048,7 @@ struct graph_t public: // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. hb_vector_t<vertex_t> vertices_; + hb_vector_t<vertex_t> vertices_scratch_; private: bool parents_invalid; bool distance_invalid; @@ -1104,8 +1057,9 @@ struct graph_t hb_vector_t<unsigned> num_roots_for_space_; }; -static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows, - graph_t& sorted_graph) +static inline +bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows, + graph_t& sorted_graph) { unsigned space = 0; hb_set_t roots_to_isolate; @@ -1153,9 +1107,10 @@ static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record return true; } -static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows, - hb_set_t& priority_bumped_parents, - graph_t& sorted_graph) +static inline +bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows, + hb_set_t& priority_bumped_parents, + graph_t& sorted_graph) { bool resolution_attempted = false; @@ -1213,14 +1168,14 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o * For a detailed writeup describing how the algorithm operates see: * docs/repacker.md */ +template<typename T> inline hb_blob_t* -hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed, +hb_resolve_overflows (const T& packed, hb_tag_t table_tag, unsigned max_rounds = 20) { // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts // so try it first to save time. graph_t sorted_graph (packed); - sorted_graph.sort_kahn (); if (!sorted_graph.will_overflow ()) { return sorted_graph.serialize (); diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh index 823c0be8b5..5663b290c3 100644 --- a/thirdparty/harfbuzz/src/hb-serialize.hh +++ b/thirdparty/harfbuzz/src/hb-serialize.hh @@ -36,6 +36,9 @@ #include "hb-map.hh" #include "hb-pool.hh" +#ifdef HB_EXPERIMENTAL_API +#include "hb-subset-repacker.h" +#endif /* * Serialize @@ -70,6 +73,33 @@ struct hb_serialize_context_t virtual_links.fini (); } + object_t () = default; + +#ifdef HB_EXPERIMENTAL_API + object_t (const hb_object_t &o) + { + head = o.head; + tail = o.tail; + next = nullptr; + real_links.alloc (o.num_real_links); + for (unsigned i = 0 ; i < o.num_real_links; i++) + real_links.push (o.real_links[i]); + + virtual_links.alloc (o.num_virtual_links); + for (unsigned i = 0; i < o.num_virtual_links; i++) + virtual_links.push (o.virtual_links[i]); + } +#endif + + friend void swap (object_t& a, object_t& b) + { + hb_swap (a.head, b.head); + hb_swap (a.tail, b.tail); + hb_swap (a.next, b.next); + hb_swap (a.real_links, b.real_links); + hb_swap (a.virtual_links, b.virtual_links); + } + bool operator == (const object_t &o) const { // Virtual links aren't considered for equality since they don't affect the functionality @@ -90,11 +120,25 @@ struct hb_serialize_context_t struct link_t { unsigned width: 3; - bool is_signed: 1; + unsigned is_signed: 1; unsigned whence: 2; - unsigned position: 28; - unsigned bias; + unsigned bias : 26; + unsigned position; objidx_t objidx; + + link_t () = default; + +#ifdef HB_EXPERIMENTAL_API + link_t (const hb_link_t &o) + { + width = o.width; + is_signed = 0; + whence = 0; + position = o.position; + bias = 0; + objidx = o.objidx; + } +#endif }; char *head; @@ -279,7 +323,7 @@ struct hb_serialize_context_t object_pool.release (obj); } - /* Set share to false when an object is unlikely sharable with others + /* Set share to false when an object is unlikely shareable with others * so not worth an attempt, or a contiguous table is serialized as * multiple consecutive objects in the reverse order so can't be shared. */ @@ -381,7 +425,7 @@ struct hb_serialize_context_t // Adding a virtual link from object a to object b will ensure that object b is always packed after // object a in the final serialized order. // - // This is useful in certain situtations where there needs to be a specific ordering in the + // This is useful in certain situations where there needs to be a specific ordering in the // final serialization. Such as when platform bugs require certain orderings, or to provide // guidance to the repacker for better offset overflow resolution. void add_virtual_link (objidx_t objidx) @@ -510,7 +554,7 @@ struct hb_serialize_context_t { return reinterpret_cast<Type *> (this->head); } template <typename Type> Type *start_embed (const Type &obj) const - { return start_embed (hb_addressof (obj)); } + { return start_embed (std::addressof (obj)); } bool err (hb_serialize_error_t err_type) { @@ -548,7 +592,7 @@ struct hb_serialize_context_t } template <typename Type> Type *embed (const Type &obj) - { return embed (hb_addressof (obj)); } + { return embed (std::addressof (obj)); } template <typename Type, typename ...Ts> auto _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN @@ -595,19 +639,19 @@ struct hb_serialize_context_t } template <typename Type> Type *extend_size (Type &obj, size_t size) - { return extend_size (hb_addressof (obj), size); } + { return extend_size (std::addressof (obj), size); } template <typename Type> Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); } template <typename Type> - Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); } + Type *extend_min (Type &obj) { return extend_min (std::addressof (obj)); } template <typename Type, typename ...Ts> Type *extend (Type *obj, Ts&&... ds) { return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); } template <typename Type, typename ...Ts> Type *extend (Type &obj, Ts&&... ds) - { return extend (hb_addressof (obj), std::forward<Ts> (ds)...); } + { return extend (std::addressof (obj), std::forward<Ts> (ds)...); } /* Output routines. */ hb_bytes_t copy_bytes () const diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc index 204dbb5645..0e2c1f77ef 100644 --- a/thirdparty/harfbuzz/src/hb-set.cc +++ b/thirdparty/harfbuzz/src/hb-set.cc @@ -257,6 +257,29 @@ hb_set_add (hb_set_t *set, } /** + * hb_set_add_sorted_array: + * @set: A set + * @sorted_codepoints: (array length=num_codepoints): Array of codepoints to add + * @num_codepoints: Length of @sorted_codepoints + * + * Adds @num_codepoints codepoints to a set at once. + * The codepoints array must be in increasing order, + * with size at least @num_codepoints. + * + * Since: 4.1.0 + */ +HB_EXTERN void +hb_set_add_sorted_array (hb_set_t *set, + const hb_codepoint_t *sorted_codepoints, + unsigned int num_codepoints) +{ + /* Immutible-safe. */ + set->add_sorted_array (sorted_codepoints, + num_codepoints, + sizeof(hb_codepoint_t)); +} + +/** * hb_set_add_range: * @set: A set * @first: The first element to add to @set @@ -591,3 +614,28 @@ hb_set_previous_range (const hb_set_t *set, { return set->previous_range (first, last); } + +/** + * hb_set_next_many: + * @set: A set + * @codepoint: Outputting codepoints starting after this one. + * Use #HB_SET_VALUE_INVALID to get started. + * @out: (array length=size): An array of codepoints to write to. + * @size: The maximum number of codepoints to write out. + * + * Finds the next element in @set that is greater than @codepoint. Writes out + * codepoints to @out, until either the set runs out of elements, or @size + * codepoints are written, whichever comes first. + * + * Return value: the number of values written. + * + * Since: 4.2.0 + **/ +unsigned int +hb_set_next_many (const hb_set_t *set, + hb_codepoint_t codepoint, + hb_codepoint_t *out, + unsigned int size) +{ + return set->next_many (codepoint, out, size); +} diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h index 423225bf96..10ce7c10d4 100644 --- a/thirdparty/harfbuzz/src/hb-set.h +++ b/thirdparty/harfbuzz/src/hb-set.h @@ -111,6 +111,11 @@ hb_set_add_range (hb_set_t *set, hb_codepoint_t last); HB_EXTERN void +hb_set_add_sorted_array (hb_set_t *set, + const hb_codepoint_t *sorted_codepoints, + unsigned int num_codepoints); + +HB_EXTERN void hb_set_del (hb_set_t *set, hb_codepoint_t codepoint); @@ -180,6 +185,12 @@ hb_set_previous_range (const hb_set_t *set, hb_codepoint_t *first, hb_codepoint_t *last); +/* Pass HB_SET_VALUE_INVALID in to get started. */ +HB_EXTERN unsigned int +hb_set_next_many (const hb_set_t *set, + hb_codepoint_t codepoint, + hb_codepoint_t *out, + unsigned int size); HB_END_DECLS diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh index af02e9e12b..6025626363 100644 --- a/thirdparty/harfbuzz/src/hb-set.hh +++ b/thirdparty/harfbuzz/src/hb-set.hh @@ -43,8 +43,8 @@ struct hb_sparseset_t hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); } hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); } - hb_sparseset_t& operator= (const hb_sparseset_t& other) { set (other); return *this; } - hb_sparseset_t& operator= (hb_sparseset_t&& other) { hb_swap (*this, other); return *this; } + hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; } + hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; } friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); } hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t () @@ -53,7 +53,7 @@ struct hb_sparseset_t add (item); } template <typename Iterable, - hb_requires (hb_is_iterable (Iterable))> + hb_requires (hb_is_iterable (Iterable))> hb_sparseset_t (const Iterable &o) : hb_sparseset_t () { hb_copy (o, *this); @@ -77,10 +77,12 @@ struct hb_sparseset_t void err () { s.err (); } bool in_error () const { return s.in_error (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); } void clear () { s.clear (); } void invert () { s.invert (); } bool is_empty () const { return s.is_empty (); } + uint32_t hash () const { return s.hash (); } 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); } @@ -109,6 +111,7 @@ struct hb_sparseset_t typedef bool value_t; value_t operator [] (hb_codepoint_t k) const { return get (k); } bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } @@ -124,6 +127,8 @@ struct hb_sparseset_t void set (const hb_sparseset_t &other) { s.set (other.s); } bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); } + bool operator == (const hb_set_t &other) const { return is_equal (other); } + bool operator != (const hb_set_t &other) const { return !is_equal (other); } bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); } @@ -138,6 +143,8 @@ struct hb_sparseset_t { return s.next_range (first, last); } bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const { return s.previous_range (first, last); } + unsigned int next_many (hb_codepoint_t codepoint, hb_codepoint_t *out, unsigned int size) const + { return s.next_many (codepoint, out, size); } unsigned int get_population () const { return s.get_population (); } hb_codepoint_t get_min () const { return s.get_min (); } @@ -155,15 +162,19 @@ struct hb_sparseset_t struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> { - hb_set_t () = default; + using sparseset = hb_sparseset_t<hb_bit_set_invertible_t>; + ~hb_set_t () = default; - hb_set_t (hb_set_t&) = default; - hb_set_t& operator= (const hb_set_t&) = default; - hb_set_t& operator= (hb_set_t&&) = default; - hb_set_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_t> (lst) {} + hb_set_t () : sparseset () {}; + hb_set_t (std::nullptr_t) : hb_set_t () {}; + hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {}; + hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {} + hb_set_t& operator = (const hb_set_t&) = default; + hb_set_t& operator = (hb_set_t&&) = default; + hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {} template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> - hb_set_t (const Iterable &o) : hb_sparseset_t<hb_bit_set_invertible_t> (o) {} + hb_set_t (const Iterable &o) : sparseset (o) {} }; static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, ""); diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc index c1f619c81c..3407e1af42 100644 --- a/thirdparty/harfbuzz/src/hb-shape.cc +++ b/thirdparty/harfbuzz/src/hb-shape.cc @@ -126,6 +126,13 @@ hb_shape_full (hb_font_t *font, unsigned int num_features, const char * const *shaper_list) { + hb_buffer_t *text_buffer = nullptr; + if (buffer->flags & HB_BUFFER_FLAG_VERIFY) + { + text_buffer = hb_buffer_create (); + hb_buffer_append (text_buffer, buffer, 0, -1); + } + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props, features, num_features, font->coords, font->num_coords, @@ -133,6 +140,17 @@ hb_shape_full (hb_font_t *font, hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); hb_shape_plan_destroy (shape_plan); + if (text_buffer) + { + if (res && !buffer->verify (text_buffer, + font, + features, + num_features, + shaper_list)) + res = false; + hb_buffer_destroy (text_buffer); + } + return res; } diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc index ec4b241470..7cc51be611 100644 --- a/thirdparty/harfbuzz/src/hb-static.cc +++ b/thirdparty/harfbuzz/src/hb-static.cc @@ -33,6 +33,7 @@ #include "hb-aat-layout-feat-table.hh" #include "hb-ot-layout-common.hh" #include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" #include "hb-ot-head-table.hh" #include "hb-ot-maxp-table.hh" @@ -55,17 +56,43 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; /* hb_face_t */ +#ifndef HB_NO_BORING_EXPANSION +static inline unsigned +load_num_glyphs_from_loca (const hb_face_t *face) +{ + unsigned ret = 0; + + unsigned indexToLocFormat = face->table.head->indexToLocFormat; + + if (indexToLocFormat <= 1) + { + bool short_offset = 0 == indexToLocFormat; + hb_blob_t *loca_blob = face->table.loca.get_blob (); + ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1; + } + + return ret; +} +#endif + +static inline unsigned +load_num_glyphs_from_maxp (const hb_face_t *face) +{ + return face->table.maxp->get_num_glyphs (); +} + unsigned int hb_face_t::load_num_glyphs () const { - hb_sanitize_context_t c = hb_sanitize_context_t (); - c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */ - hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this); - const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> (); + unsigned ret = 0; + +#ifndef HB_NO_BORING_EXPANSION + ret = hb_max (ret, load_num_glyphs_from_loca (this)); +#endif + + ret = hb_max (ret, load_num_glyphs_from_maxp (this)); - unsigned int ret = maxp_table->get_num_glyphs (); num_glyphs.set_relaxed (ret); - hb_blob_destroy (maxp_blob); return ret; } diff --git a/thirdparty/harfbuzz/src/hb-style.cc b/thirdparty/harfbuzz/src/hb-style.cc index f1b44cea53..c7d7d713c2 100644 --- a/thirdparty/harfbuzz/src/hb-style.cc +++ b/thirdparty/harfbuzz/src/hb-style.cc @@ -46,15 +46,14 @@ static inline float _hb_angle_to_ratio (float a) { - return tanf (a * float (M_PI / 180.)); + return tanf (a * float (-M_PI / 180.)); } -#if 0 + static inline float _hb_ratio_to_angle (float r) { - return atanf (r) * float (180. / M_PI); + return atanf (r) * float (-180. / M_PI); } -#endif /** * hb_style_get_value: @@ -109,7 +108,14 @@ hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag) : 12.f; } case HB_STYLE_TAG_SLANT_ANGLE: - return face->table.post->table->italicAngle.to_float (); + { + float angle = face->table.post->table->italicAngle.to_float (); + + if (font->slant) + angle = _hb_ratio_to_angle (font->slant + _hb_angle_to_ratio (angle)); + + return angle; + } case HB_STYLE_TAG_WIDTH: return face->table.OS2->has_data () ? face->table.OS2->get_width () diff --git a/thirdparty/harfbuzz/src/hb-style.h b/thirdparty/harfbuzz/src/hb-style.h index 30a6f2b878..d17d2daa5f 100644 --- a/thirdparty/harfbuzz/src/hb-style.h +++ b/thirdparty/harfbuzz/src/hb-style.h @@ -43,8 +43,10 @@ HB_BEGIN_DECLS * @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values * must be greater than -90 and less than +90. Values can be interpreted as * the angle, in counter-clockwise degrees, of oblique slant from whatever the - * designer considers to be upright for that font design. + * designer considers to be upright for that font design. Typical right-leaning + * Italic fonts have a negative slant angle (typically around -12) * @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio. + * Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2) * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider. * Non-zero. Values can be interpreted as a percentage of whatever the font * designer considers “normal width” for that font design. diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh index 7fd96ca86d..ae155b4e3c 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh @@ -40,7 +40,7 @@ struct str_encoder_t str_encoder_t (str_buff_t &buff_) : buff (buff_), error (false) {} - void reset () { buff.resize (0); } + void reset () { buff.reset (); } void encode_byte (unsigned char b) { @@ -107,20 +107,18 @@ struct str_encoder_t encode_byte (op); } - void copy_str (const byte_str_t &str) + void copy_str (const hb_ubytes_t &str) { unsigned int offset = buff.length; - if (unlikely (!buff.resize (offset + str.length))) + /* Manually resize buffer since faster. */ + if ((signed) (buff.length + str.length) <= buff.allocated) + buff.length += str.length; + else if (unlikely (!buff.resize (offset + str.length))) { set_error (); return; } - if (unlikely (buff.length < offset + str.length)) - { - set_error (); - return; - } - memcpy (&buff[offset], &str[0], str.length); + memcpy (buff.arrayZ + offset, &str[0], str.length); } bool is_error () const { return error; } @@ -253,12 +251,12 @@ struct subr_flattener_t if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); continue; } - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t<ENV, OPSET, flatten_param_t> interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env); flatten_param_t param = { flat_charstrings[i], (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -275,60 +273,36 @@ struct subr_flattener_t struct subr_closures_t { - subr_closures_t () : valid (false), global_closure (nullptr) - { local_closures.init (); } - - void init (unsigned int fd_count) + subr_closures_t (unsigned int fd_count) : valid (false), global_closure (), local_closures () { valid = true; - global_closure = hb_set_create (); - if (global_closure == hb_set_get_empty ()) - valid = false; if (!local_closures.resize (fd_count)) valid = false; - - for (unsigned int i = 0; i < local_closures.length; i++) - { - local_closures[i] = hb_set_create (); - if (local_closures[i] == hb_set_get_empty ()) - valid = false; - } - } - - void fini () - { - hb_set_destroy (global_closure); - for (unsigned int i = 0; i < local_closures.length; i++) - hb_set_destroy (local_closures[i]); - local_closures.fini (); } void reset () { - hb_set_clear (global_closure); + global_closure.clear(); for (unsigned int i = 0; i < local_closures.length; i++) - hb_set_clear (local_closures[i]); + local_closures[i].clear(); } bool is_valid () const { return valid; } bool valid; - hb_set_t *global_closure; - hb_vector_t<hb_set_t *> local_closures; + hb_set_t global_closure; + hb_vector_t<hb_set_t> local_closures; }; struct parsed_cs_op_t : op_str_t { void init (unsigned int subr_num_ = 0) { - op_str_t::init (); subr_num = subr_num_; drop_flag = false; keep_flag = false; skip_flag = false; } - void fini () { op_str_t::fini (); } - bool for_drop () const { return drop_flag; } void set_drop () { if (!for_keep ()) drop_flag = true; } @@ -341,9 +315,9 @@ struct parsed_cs_op_t : op_str_t unsigned int subr_num; protected: - bool drop_flag : 1; - bool keep_flag : 1; - bool skip_flag : 1; + bool drop_flag; + bool keep_flag; + bool skip_flag; }; struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> @@ -416,35 +390,25 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> { - void init (unsigned int len_ = 0) - { - SUPER::init (); - if (unlikely (!resize (len_))) - return; - for (unsigned int i = 0; i < length; i++) - (*this)[i].init (); - } - void fini () { SUPER::fini_deep (); } - private: typedef hb_vector_t<parsed_cs_str_t> SUPER; }; struct subr_subset_param_t { - void init (parsed_cs_str_t *parsed_charstring_, - parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_, - hb_set_t *global_closure_, hb_set_t *local_closure_, - bool drop_hints_) - { - parsed_charstring = parsed_charstring_; - current_parsed_str = parsed_charstring; - parsed_global_subrs = parsed_global_subrs_; - parsed_local_subrs = parsed_local_subrs_; - global_closure = global_closure_; - local_closure = local_closure_; - drop_hints = drop_hints_; - } + subr_subset_param_t (parsed_cs_str_t *parsed_charstring_, + parsed_cs_str_vec_t *parsed_global_subrs_, + parsed_cs_str_vec_t *parsed_local_subrs_, + hb_set_t *global_closure_, + hb_set_t *local_closure_, + bool drop_hints_) : + current_parsed_str (parsed_charstring_), + parsed_charstring (parsed_charstring_), + parsed_global_subrs (parsed_global_subrs_), + parsed_local_subrs (parsed_local_subrs_), + global_closure (global_closure_), + local_closure (local_closure_), + drop_hints (drop_hints_) {} parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) { @@ -496,12 +460,13 @@ struct subr_subset_param_t struct subr_remap_t : hb_inc_bimap_t { - void create (hb_set_t *closure) + void create (const hb_set_t *closure) { /* create a remapping of subroutine numbers from old to new. * no optimization based on usage counts. fonttools doesn't appear doing that either. */ + resize (closure->get_population ()); hb_codepoint_t old_num = HB_SET_VALUE_INVALID; while (hb_set_next (closure, &old_num)) add (old_num); @@ -526,19 +491,9 @@ struct subr_remap_t : hb_inc_bimap_t struct subr_remaps_t { - subr_remaps_t () + subr_remaps_t (unsigned int fdCount) { - global_remap.init (); - local_remaps.init (); - } - - ~subr_remaps_t () { fini (); } - - void init (unsigned int fdCount) - { - if (unlikely (!local_remaps.resize (fdCount))) return; - for (unsigned int i = 0; i < fdCount; i++) - local_remaps[i].init (); + local_remaps.resize (fdCount); } bool in_error() @@ -548,15 +503,9 @@ struct subr_remaps_t void create (subr_closures_t& closures) { - global_remap.create (closures.global_closure); + global_remap.create (&closures.global_closure); for (unsigned int i = 0; i < local_remaps.length; i++) - local_remaps[i].create (closures.local_closures[i]); - } - - void fini () - { - global_remap.fini (); - local_remaps.fini_deep (); + local_remaps[i].create (&closures.local_closures[i]); } subr_remap_t global_remap; @@ -567,21 +516,8 @@ template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typena struct subr_subsetter_t { subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_) - : acc (acc_), plan (plan_) - { - parsed_charstrings.init (); - parsed_global_subrs.init (); - parsed_local_subrs.init (); - } - - ~subr_subsetter_t () - { - closures.fini (); - remaps.fini (); - parsed_charstrings.fini_deep (); - parsed_global_subrs.fini_deep (); - parsed_local_subrs.fini_deep (); - } + : acc (acc_), plan (plan_), closures(acc_.fdCount), remaps(acc_.fdCount) + {} /* Subroutine subsetting with --no-desubroutinize runs in phases: * @@ -599,11 +535,8 @@ struct subr_subsetter_t */ bool subset (void) { - closures.init (acc.fdCount); - remaps.init (acc.fdCount); - - parsed_charstrings.init (plan->num_output_glyphs ()); - parsed_global_subrs.init (acc.globalSubrs->count); + parsed_charstrings.resize (plan->num_output_glyphs ()); + parsed_global_subrs.resize (acc.globalSubrs->count); if (unlikely (remaps.in_error() || parsed_charstrings.in_error () @@ -615,7 +548,7 @@ struct subr_subsetter_t for (unsigned int i = 0; i < acc.fdCount; i++) { - parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); + parsed_local_subrs[i].resize (acc.privateDicts[i].localSubrs->count); if (unlikely (parsed_local_subrs[i].in_error ())) return false; } if (unlikely (!closures.valid)) @@ -627,19 +560,21 @@ struct subr_subsetter_t hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) continue; - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + parsed_charstrings[i].alloc (str.length); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); if (unlikely (!interp.interpret (param))) return false; @@ -659,11 +594,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); drop_hints_param_t drop; if (drop_hints_in_str (parsed_charstrings[i], param, drop)) @@ -684,11 +620,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); collect_subr_refs_in_str (parsed_charstrings[i], param); } } @@ -915,9 +852,10 @@ struct subr_subsetter_t bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const { - buff.init (); + unsigned count = str.get_count (); str_encoder_t encoder (buff); encoder.reset (); + buff.alloc (count * 3); /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, * re-insert it at the beginning of charstreing */ if (str.has_prefix () && str.is_hint_dropped ()) @@ -926,7 +864,7 @@ struct subr_subsetter_t if (str.prefix_op () != OpCode_Invalid) encoder.encode_op (str.prefix_op ()); } - for (unsigned int i = 0; i < str.get_count(); i++) + for (unsigned int i = 0; i < count; i++) { const parsed_cs_op_t &opstr = str.values[i]; if (!opstr.for_drop () && !opstr.for_skip ()) diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc index b4e24122c9..52bb13d320 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc @@ -169,7 +169,7 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic supp_op.op = op; if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3))) return_trace (false); - supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); + supp_op.str = hb_ubytes_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) && UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && copy_opstr (c, supp_op)); @@ -270,13 +270,13 @@ struct range_list_t : hb_vector_t<code_pair_t> /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ bool complete (unsigned int last_glyph) { - bool two_byte = false; - for (unsigned int i = (*this).length; i > 0; i--) + bool two_byte = false; + unsigned count = this->length; + for (unsigned int i = count; i; i--) { - code_pair_t &pair = (*this)[i - 1]; - unsigned int nLeft = last_glyph - pair.glyph - 1; - if (nLeft >= 0x100) - two_byte = true; + code_pair_t &pair = arrayZ[i - 1]; + unsigned int nLeft = last_glyph - pair.glyph - 1; + two_byte |= nLeft >= 0x100; last_glyph = pair.glyph; pair.glyph = nLeft; } @@ -362,43 +362,11 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs struct cff_subset_plan { cff_subset_plan () - : info (), - orig_fdcount (0), - subset_fdcount (1), - subset_fdselect_format (0), - drop_hints (false), - desubroutinize(false) { - topdict_mod.init (); - subset_fdselect_ranges.init (); - fdmap.init (); - subset_charstrings.init (); - subset_globalsubrs.init (); - subset_localsubrs.init (); - fontdicts_mod.init (); - subset_enc_code_ranges.init (); - subset_enc_supp_codes.init (); - subset_charset_ranges.init (); - sidmap.init (); for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) topDictModSIDs[i] = CFF_UNDEF_SID; } - ~cff_subset_plan () - { - topdict_mod.fini (); - subset_fdselect_ranges.fini (); - fdmap.fini (); - subset_charstrings.fini_deep (); - subset_globalsubrs.fini_deep (); - subset_localsubrs.fini_deep (); - fontdicts_mod.fini (); - subset_enc_code_ranges.fini (); - subset_enc_supp_codes.fini (); - subset_charset_ranges.fini (); - sidmap.fini (); - } - void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { const Encoding *encoding = acc.encoding; @@ -474,6 +442,9 @@ struct cff_subset_plan { return; } + bool use_glyph_to_sid_map = plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.; + hb_map_t *glyph_to_sid_map = use_glyph_to_sid_map ? acc.create_glyph_to_sid_map () : nullptr; + unsigned int glyph; for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { @@ -483,7 +454,7 @@ struct cff_subset_plan { /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - sid = acc.glyph_to_sid (old_glyph); + sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph); if (!acc.is_CID ()) sid = sidmap.add (sid); @@ -496,6 +467,9 @@ struct cff_subset_plan { last_sid = sid; } + if (glyph_to_sid_map) + hb_map_destroy (glyph_to_sid_map); + bool two_byte = subset_charset_ranges.complete (glyph); size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); @@ -672,9 +646,9 @@ struct cff_subset_plan { cff1_sub_table_info_t info; unsigned int num_glyphs; - unsigned int orig_fdcount; - unsigned int subset_fdcount; - unsigned int subset_fdselect_format; + unsigned int orig_fdcount = 0; + unsigned int subset_fdcount = 1; + unsigned int subset_fdselect_format = 0; hb_vector_t<code_pair_t> subset_fdselect_ranges; /* font dict index remap table from fullset FDArray to subset FDArray. @@ -686,7 +660,7 @@ struct cff_subset_plan { hb_vector_t<str_buff_vec_t> subset_localsubrs; hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod; - bool drop_hints; + bool drop_hints = false; bool gid_renum; bool subset_encoding; @@ -702,7 +676,7 @@ struct cff_subset_plan { remap_sid_t sidmap; unsigned int topDictModSIDs[name_dict_values_t::ValCount]; - bool desubroutinize; + bool desubroutinize = false; }; static bool _serialize_cff1 (hb_serialize_context_t *c, diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc index 896ae64016..08e820efcf 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc @@ -67,9 +67,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> } }; -struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> +struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> { - static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { switch (op) { @@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte } } - static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_args (cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { for (unsigned int i = 0; i < env.argStack.get_count ();) { @@ -122,7 +122,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte SUPER::flush_args (env, param); } - static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { /* flatten the default values */ str_encoder_t encoder (param.flatStr); @@ -149,7 +149,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte encoder.encode_op (OpCode_blendcs); } - static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { switch (op) { @@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte } private: - typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER; - typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET; + typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER; + typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_t>, flatten_param_t> CSOPSET; }; -struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> +struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param) { switch (op) { @@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t protected: static void process_call_subr (op_code_t op, cs_type_t type, - cff2_cs_interp_env_t &env, subr_subset_param_t& param, + cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, cff2_biased_subrs_t& subrs, hb_set_t *closure) { byte_str_ref_t str_ref = env.str_ref; @@ -212,15 +212,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t } private: - typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; + typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> SUPER; }; -struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t> +struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_subr_subset_t> { cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) : subr_subsetter_t (acc_, plan_) {} - static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + static void complete_parsed_str (cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) { /* vsindex is inserted at the beginning of the charstring as necessary */ if (env.seen_vsindex ()) @@ -233,29 +233,6 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs }; struct cff2_subset_plan { - cff2_subset_plan () - : orig_fdcount (0), - subset_fdcount(1), - subset_fdselect_size (0), - subset_fdselect_format (0), - drop_hints (false), - desubroutinize (false) - { - subset_fdselect_ranges.init (); - fdmap.init (); - subset_charstrings.init (); - subset_globalsubrs.init (); - subset_localsubrs.init (); - } - - ~cff2_subset_plan () - { - subset_fdselect_ranges.fini (); - fdmap.fini (); - subset_charstrings.fini_deep (); - subset_globalsubrs.fini_deep (); - subset_localsubrs.fini_deep (); - } bool create (const OT::cff2::accelerator_subset_t &acc, hb_subset_plan_t *plan) @@ -268,7 +245,7 @@ struct cff2_subset_plan { if (desubroutinize) { /* Flatten global & local subrs */ - subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t> + subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t> flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; @@ -320,10 +297,10 @@ struct cff2_subset_plan { cff2_sub_table_info_t info; - unsigned int orig_fdcount; - unsigned int subset_fdcount; - unsigned int subset_fdselect_size; - unsigned int subset_fdselect_format; + unsigned int orig_fdcount = 0; + unsigned int subset_fdcount = 1; + unsigned int subset_fdselect_size = 0; + unsigned int subset_fdselect_format = 0; hb_vector_t<code_pair_t> subset_fdselect_ranges; hb_inc_bimap_t fdmap; @@ -332,8 +309,8 @@ struct cff2_subset_plan { str_buff_vec_t subset_globalsubrs; hb_vector_t<str_buff_vec_t> subset_localsubrs; - bool drop_hints; - bool desubroutinize; + bool drop_hints = false; + bool desubroutinize = false; }; static bool _serialize_cff2 (hb_serialize_context_t *c, @@ -473,12 +450,8 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, bool hb_subset_cff2 (hb_subset_context_t *c) { - OT::cff2::accelerator_subset_t acc; - acc.init (c->plan->source); - bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c); - acc.fini (); - - return result; + OT::cff2::accelerator_subset_t acc (c->plan->source); + return acc.is_valid () && _hb_subset_cff2 (acc, c); } #endif diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index 883ab82093..a62ae8e024 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -40,6 +40,8 @@ #include "hb-ot-stat-table.hh" #include "hb-ot-math-table.hh" +using OT::Layout::GSUB::GSUB; + typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map; #ifndef HB_NO_SUBSET_CFF @@ -111,7 +113,7 @@ static void _collect_layout_indices (hb_face_t *face, retain_all_features = false; continue; } - + if (visited_features.has (tag)) continue; @@ -228,10 +230,8 @@ _cmap_closure (hb_face_t *face, const hb_set_t *unicodes, hb_set_t *glyphset) { - OT::cmap::accelerator_t cmap; - cmap.init (face); + OT::cmap::accelerator_t cmap (face); cmap.table->closure_glyphs (unicodes, glyphset); - cmap.fini (); } static void _colr_closure (hb_face_t *face, @@ -239,8 +239,7 @@ static void _colr_closure (hb_face_t *face, hb_map_t *palettes_map, hb_set_t *glyphs_colred) { - OT::COLR::accelerator_t colr; - colr.init (face); + OT::COLR::accelerator_t colr (face); if (!colr.is_valid ()) return; unsigned iteration_count = 0; @@ -252,9 +251,9 @@ static void _colr_closure (hb_face_t *face, hb_set_t glyphset_colrv0; for (hb_codepoint_t gid : glyphs_colred->iter ()) colr.closure_glyphs (gid, &glyphset_colrv0); - + glyphs_colred->union_ (glyphset_colrv0); - + //closure for COLRv1 colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices); } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && @@ -263,7 +262,6 @@ static void _colr_closure (hb_face_t *face, colr.closure_V0palette_indices (glyphs_colred, &palette_indices); _remap_indexes (&layer_indices, layers_map); _remap_palette_indexes (&palette_indices, palettes_map); - colr.fini (); } static inline void @@ -281,12 +279,7 @@ static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { - hb_codepoint_t gid = HB_SET_VALUE_INVALID; - while (glyphs->next (&gid)) - { - if (gid >= num_glyphs) - glyphs->del (gid); - } + glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID); } static void @@ -294,15 +287,15 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, const hb_set_t *glyphs, hb_subset_plan_t *plan) { - OT::cmap::accelerator_t cmap; - cmap.init (plan->source); - - constexpr static const int size_threshold = 4096; + OT::cmap::accelerator_t cmap (plan->source); + unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes->get_population () < size_threshold) { - /* This is the fast path if it's anticipated that size of unicodes - * is << than the number of codepoints in the font. */ + // This is approach to collection is faster, but can only be used if glyphs + // are not being explicitly added to the subset and the input unicodes set is + // not excessively large (eg. an inverted set). + plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); for (hb_codepoint_t cp : *unicodes) { hb_codepoint_t gid; @@ -313,27 +306,32 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } } else { + // This approach is slower, but can handle adding in glyphs to the subset and will match + // them with cmap entries. hb_map_t unicode_glyphid_map; - cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map); + hb_set_t cmap_unicodes; + cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map); + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + + glyphs->get_population (), + cmap_unicodes.get_population ())); - for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid : - + unicode_glyphid_map.iter ()) + for (hb_codepoint_t cp : cmap_unicodes) { - if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second)) - continue; + hb_codepoint_t gid = unicode_glyphid_map[cp]; + if (!unicodes->has (cp) && !glyphs->has (gid)) + continue; - plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second); + plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } /* Add gids which where requested, but not mapped in cmap */ - // TODO(garretrieger): - // Once https://github.com/harfbuzz/harfbuzz/issues/3169 - // is implemented, this can be done with union and del_range - for (hb_codepoint_t gid : glyphs->iter ()) + for (hb_codepoint_t gid : *glyphs) { if (gid >= plan->source->get_num_glyphs ()) break; @@ -341,10 +339,12 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } } - + plan->codepoint_to_glyph->keys () | hb_sink (plan->unicodes); - + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub); - - cmap.fini (); + auto &arr = plan->unicode_to_new_gid_list; + if (arr.length) + { + plan->unicodes->add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ)); + plan->_glyphset_gsub->add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ)); + } } static void @@ -353,13 +353,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, bool close_over_gpos, bool close_over_gdef) { - OT::glyf::accelerator_t glyf; -#ifndef HB_NO_SUBSET_CFF - OT::cff1::accelerator_t cff; -#endif - glyf.init (plan->source); + OT::glyf::accelerator_t glyf (plan->source); #ifndef HB_NO_SUBSET_CFF - cff.init (plan->source); + OT::cff1::accelerator_t cff (plan->source); #endif plan->_glyphset_gsub->add (0); // Not-def @@ -369,7 +365,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #ifndef HB_NO_SUBSET_LAYOUT if (close_over_gsub) // closure all glyphs/lookups/features needed for GSUB substitutions. - _closure_glyphs_lookups_features<OT::GSUB> ( + _closure_glyphs_lookups_features<GSUB> ( plan->source, plan->_glyphset_gsub, plan->layout_features, @@ -397,16 +393,19 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); hb_set_set (plan->_glyphset_colred, &cur_glyphset); - // Populate a full set of glyphs to retain by adding all referenced - // composite glyphs. - for (hb_codepoint_t gid : cur_glyphset.iter ()) - { - glyf.add_gid_and_children (gid, plan->_glyphset); + + /* Populate a full set of glyphs to retain by adding all referenced + * composite glyphs. */ + if (glyf.has_data ()) + for (hb_codepoint_t gid : cur_glyphset) + glyf.add_gid_and_children (gid, plan->_glyphset); + else + plan->_glyphset->union_ (cur_glyphset); #ifndef HB_NO_SUBSET_CFF - if (cff.is_valid ()) + if (cff.is_valid ()) + for (hb_codepoint_t gid : cur_glyphset) _add_cff_seac_components (cff, gid, plan->_glyphset); #endif - } _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); @@ -419,11 +418,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->layout_variation_indices, plan->layout_variation_idx_map); #endif +} -#ifndef HB_NO_SUBSET_CFF - cff.fini (); -#endif - glyf.fini (); +static void +_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, + const hb_map_t* glyph_map, + hb_map_t* out) +{ + + hb_iter (glyph_set_gsub) + | hb_map ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, + glyph_map->get (gid)); + }) + | hb_sink (out) + ; } static void @@ -434,13 +442,19 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) { + unsigned pop = all_gids_to_retain->get_population (); + reverse_glyph_map->resize (pop); + glyph_map->resize (pop); + if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) | hb_sink (reverse_glyph_map) ; *num_glyphs = reverse_glyph_map->get_population (); - } else { + } + else + { + hb_iter (all_gids_to_retain) | hb_map ([] (hb_codepoint_t _) { return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _); @@ -448,10 +462,9 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, | hb_sink (reverse_glyph_map) ; - unsigned max_glyph = - + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0u) - ; + hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; + hb_set_previous (all_gids_to_retain, &max_glyph); + *num_glyphs = max_glyph + 1; } @@ -474,7 +487,7 @@ _nameid_closure (hb_face_t *face, } /** - * hb_subset_plan_create: + * hb_subset_plan_create_or_fail: * @face: font face to create the plan for. * @input: a #hb_subset_input_t input. * @@ -483,21 +496,25 @@ _nameid_closure (hb_face_t *face, * which tables and glyphs should be retained. * * Return value: (transfer full): New subset plan. Destroy with - * hb_subset_plan_destroy(). + * hb_subset_plan_destroy(). If there is a failure creating the plan + * nullptr will be returned. * - * Since: 1.7.5 + * Since: 4.0.0 **/ hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - const hb_subset_input_t *input) +hb_subset_plan_create_or_fail (hb_face_t *face, + const hb_subset_input_t *input) { hb_subset_plan_t *plan; if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ()))) - return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t)); + return nullptr; plan->successful = true; plan->flags = input->flags; plan->unicodes = hb_set_create (); + + plan->unicode_to_new_gid_list.init (); + plan->name_ids = hb_set_copy (input->sets.name_ids); _nameid_closure (face, plan->name_ids); plan->name_languages = hb_set_copy (input->sets.name_languages); @@ -515,6 +532,7 @@ hb_subset_plan_create (hb_face_t *face, plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); + plan->glyph_map_gsub = hb_map_create (); plan->gsub_lookups = hb_map_create (); plan->gpos_lookups = hb_map_create (); @@ -530,8 +548,9 @@ hb_subset_plan_create (hb_face_t *face, plan->layout_variation_indices = hb_set_create (); plan->layout_variation_idx_map = hb_map_create (); - if (plan->in_error ()) { - return plan; + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; } _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan); @@ -548,6 +567,23 @@ hb_subset_plan_create (hb_face_t *face, plan->reverse_glyph_map, &plan->_num_output_glyphs); + _create_glyph_map_gsub ( + plan->_glyphset_gsub, + plan->glyph_map, + plan->glyph_map_gsub); + + // Now that we have old to new gid map update the unicode to new gid list. + for (unsigned i = 0; i < plan->unicode_to_new_gid_list.length; i++) + { + // Use raw array access for performance. + plan->unicode_to_new_gid_list.arrayZ[i].second = + plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second); + } + + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; + } return plan; } @@ -558,7 +594,7 @@ hb_subset_plan_create (hb_face_t *face, * Decreases the reference count on @plan, and if it reaches zero, destroys * @plan, freeing all memory. * - * Since: 1.7.5 + * Since: 4.0.0 **/ void hb_subset_plan_destroy (hb_subset_plan_t *plan) @@ -566,6 +602,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); + plan->unicode_to_new_gid_list.fini (); hb_set_destroy (plan->name_ids); hb_set_destroy (plan->name_languages); hb_set_destroy (plan->layout_features); @@ -577,6 +614,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); hb_map_destroy (plan->reverse_glyph_map); + hb_map_destroy (plan->glyph_map_gsub); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_mathed); @@ -612,3 +650,116 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_free (plan); } + +/** + * hb_subset_plan_old_to_new_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the original font to glyphs in the + * subset that will be produced by @plan + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->glyph_map; +} + +/** + * hb_subset_plan_new_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the subset that will be produced by + * @plan and the glyph in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->reverse_glyph_map; +} + +/** + * hb_subset_plan_unicode_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between codepoints in the original font and the + * associated glyph id in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->codepoint_to_glyph; +} + +/** + * hb_subset_plan_reference: (skip) + * @plan: a #hb_subset_plan_t object. + * + * Increases the reference count on @plan. + * + * Return value: @plan. + * + * Since: 4.0.0 + **/ +hb_subset_plan_t * +hb_subset_plan_reference (hb_subset_plan_t *plan) +{ + return hb_object_reference (plan); +} + +/** + * hb_subset_plan_set_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to set + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the given subset plan object. + * + * Return value: %true if success, %false otherwise + * + * Since: 4.0.0 + **/ +hb_bool_t +hb_subset_plan_set_user_data (hb_subset_plan_t *plan, + hb_user_data_key_t *key, + void *data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (plan, key, data, destroy, replace); +} + +/** + * hb_subset_plan_get_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to query + * + * Fetches the user data associated with the specified key, + * attached to the specified subset plan object. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 4.0.0 + **/ +void * +hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (plan, key); +} diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh index b9244e5cb2..cb567b769e 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.hh +++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh @@ -44,6 +44,7 @@ struct hb_subset_plan_t // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; + hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list; // name_ids we would like to retain hb_set_t *name_ids; @@ -69,6 +70,7 @@ struct hb_subset_plan_t // Old -> New glyph id mapping hb_map_t *glyph_map; hb_map_t *reverse_glyph_map; + hb_map_t *glyph_map_gsub; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; @@ -198,13 +200,4 @@ struct hb_subset_plan_t } }; -typedef struct hb_subset_plan_t hb_subset_plan_t; - -HB_INTERNAL hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - const hb_subset_input_t *input); - -HB_INTERNAL void -hb_subset_plan_destroy (hb_subset_plan_t *plan); - #endif /* HB_SUBSET_PLAN_HH */ diff --git a/thirdparty/harfbuzz/src/hb-subset-repacker.cc b/thirdparty/harfbuzz/src/hb-subset-repacker.cc new file mode 100644 index 0000000000..2447d296b8 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-subset-repacker.cc @@ -0,0 +1,49 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ +#include "hb-repacker.hh" + +#ifdef HB_EXPERIMENTAL_API +/** + * hb_subset_repack_or_fail: + * @hb_objects: raw array of struct hb_object_t, which provides + * object graph info + * @num_hb_objs: number of hb_object_t in the hb_objects array. + * + * Given the input object graph info, repack a table to eliminate + * offset overflows. A nullptr is returned if the repacking attempt fails. + * + * Since: EXPERIMENTAL + **/ +hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_objs) +{ + hb_vector_t<const hb_object_t *> packed; + packed.alloc (num_hb_objs + 1); + packed.push (nullptr); + for (unsigned i = 0 ; i < num_hb_objs ; i++) + packed.push (&(hb_objects[i])); + return hb_resolve_overflows (packed, HB_OT_TAG_GSUB); +} +#endif + diff --git a/thirdparty/harfbuzz/src/hb-subset-repacker.h b/thirdparty/harfbuzz/src/hb-subset-repacker.h new file mode 100644 index 0000000000..f9a2383698 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-subset-repacker.h @@ -0,0 +1,80 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#ifndef HB_SUBSET_REPACKER_H +#define HB_SUBSET_REPACKER_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#ifdef HB_EXPERIMENTAL_API +/** + * struct hb_link_t + * width: offsetSize in bytes + * position: position of the offset field in bytes + * from beginning of subtable + * objidx: index of subtable + **/ +struct hb_link_t +{ + unsigned width; + unsigned position; + unsigned objidx; +}; + +typedef struct hb_link_t hb_link_t; + +/** + * struct hb_object_t + * head: start of object data + * tail: end of object data + * num_real_links: num of offset field in the object + * real_links: pointer to array of offset info + * num_virtual_links: num of objects that must be packed + * after current object in the final serialized order + * virtual_links: array of virtual link info + **/ +struct hb_object_t +{ + char *head; + char *tail; + unsigned num_real_links; + hb_link_t *real_links; + unsigned num_virtual_links; + hb_link_t *virtual_links; +}; + +typedef struct hb_object_t hb_object_t; + +HB_EXTERN hb_blob_t* +hb_subset_repack_or_fail (hb_object_t* hb_objects, + unsigned num_hb_objs); + +#endif + +HB_END_DECLS + +#endif /* HB_SUBSET_REPACKER_H */ diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc index bb46e5b97f..31ddb4f894 100644 --- a/thirdparty/harfbuzz/src/hb-subset.cc +++ b/thirdparty/harfbuzz/src/hb-subset.cc @@ -55,6 +55,8 @@ #include "hb-ot-math-table.hh" #include "hb-repacker.hh" +using OT::Layout::GSUB::GSUB; + /** * SECTION:hb-subset * @title: hb-subset @@ -77,12 +79,14 @@ */ static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, + unsigned table_len, + bool same_size) { unsigned src_glyphs = plan->source->get_num_glyphs (); unsigned dst_glyphs = plan->glyphset ()->get_population (); - if (unlikely (!src_glyphs)) + if (unlikely (!src_glyphs) || same_size) return 512 + table_len; return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); @@ -121,7 +125,6 @@ static bool _try_subset (const TableType *table, hb_vector_t<char>* buf, - unsigned buf_size, hb_subset_context_t* c /* OUT */) { c->serializer->start_serialize<TableType> (); @@ -134,7 +137,8 @@ _try_subset (const TableType *table, return needed; } - buf_size += (buf_size >> 1) + 32; + unsigned buf_size = buf->allocated; + buf_size = buf_size * 2 + 16; DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (c->table_tag), buf_size); @@ -145,13 +149,13 @@ _try_subset (const TableType *table, return needed; } - c->serializer->reset (buf->arrayZ, buf_size); - return _try_subset (table, buf, buf_size, c); + c->serializer->reset (buf->arrayZ, buf->allocated); + return _try_subset (table, buf, c); } template<typename TableType> static bool -_subset (hb_subset_plan_t *plan) +_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf) { hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); const TableType *table = source_blob->as<TableType> (); @@ -165,10 +169,13 @@ _subset (hb_subset_plan_t *plan) return false; } - hb_vector_t<char> buf; - /* TODO Not all tables are glyph-related. 'name' table size for example should not be - * affected by number of glyphs. Accommodate that. */ - unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB || + TableType::tableTag == HB_OT_TAG_GPOS || + TableType::tableTag == HB_OT_TAG_name; + + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length, same_size_table); DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) @@ -179,10 +186,10 @@ _subset (hb_subset_plan_t *plan) } bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf_size); + hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); { hb_subset_context_t c (source_blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, buf_size, &c); + needed = _try_subset (table, &buf, &c); } hb_blob_destroy (source_blob); @@ -272,7 +279,9 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag) } static bool -_subset_table (hb_subset_plan_t *plan, hb_tag_t tag) +_subset_table (hb_subset_plan_t *plan, + hb_vector_t<char> &buf, + hb_tag_t tag) { if (plan->no_subset_tables->has (tag)) { return _passthrough (plan, tag); @@ -281,42 +290,42 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); switch (tag) { - case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan); - case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan); - case HB_OT_TAG_name: return _subset<const OT::name> (plan); + case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf); + case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf); + case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf); case HB_OT_TAG_head: if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) return true; /* skip head, handled by glyf */ - return _subset<const OT::head> (plan); + return _subset<const OT::head> (plan, buf); case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan); + case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf); case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan); - case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan); - case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan); + case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf); + case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf); + case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf); case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan); - case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan); - case HB_OT_TAG_post: return _subset<const OT::post> (plan); - case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan); - case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan); - case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan); + case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf); + case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf); + case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf); + case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf); + case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf); + case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf); case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan); + case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf); #ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan); - case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan); - case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan); + case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf); + case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf); + case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf); #endif #ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan); - case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan); - case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan); - case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan); - case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan); - case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan); + case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf); + case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf); + case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan, buf); + case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf); + case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf); + case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf); #endif default: @@ -343,9 +352,33 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input) { if (unlikely (!input || !source)) return hb_face_get_empty (); - hb_subset_plan_t *plan = hb_subset_plan_create (source, input); - if (unlikely (plan->in_error ())) { - hb_subset_plan_destroy (plan); + hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input); + if (unlikely (!plan)) { + return nullptr; + } + + hb_face_t * result = hb_subset_plan_execute_or_fail (plan); + hb_subset_plan_destroy (plan); + return result; +} + + +/** + * hb_subset_plan_execute_or_fail: + * @plan: a subsetting plan. + * + * Executes the provided subsetting @plan. + * + * Return value: + * on success returns a reference to generated font subset. If the subsetting operation fails + * returns nullptr. + * + * Since: 4.0.0 + **/ +hb_face_t * +hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) +{ + if (unlikely (!plan || plan->in_error ())) { return nullptr; } @@ -353,22 +386,21 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input) bool success = true; hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); - while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + hb_vector_t<char> buf; + buf.alloc (4096 - 16); + while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables)) { for (unsigned i = 0; i < num_tables; ++i) { hb_tag_t tag = table_tags[i]; if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; tags_set.add (tag); - success = _subset_table (plan, tag); + success = _subset_table (plan, buf, tag); if (unlikely (!success)) goto end; } offset += num_tables; } end: - hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr; - - hb_subset_plan_destroy (plan); - return result; + return success ? hb_face_reference (plan->dest) : nullptr; } diff --git a/thirdparty/harfbuzz/src/hb-subset.h b/thirdparty/harfbuzz/src/hb-subset.h index 1c65a4da1c..a2799d91e8 100644 --- a/thirdparty/harfbuzz/src/hb-subset.h +++ b/thirdparty/harfbuzz/src/hb-subset.h @@ -40,6 +40,15 @@ HB_BEGIN_DECLS typedef struct hb_subset_input_t hb_subset_input_t; /** + * hb_subset_plan_t: + * + * Contains information about how the subset operation will be executed. + * Such as mappings from the old glyph ids to the new ones in the subset. + */ + +typedef struct hb_subset_plan_t hb_subset_plan_t; + +/** * hb_subset_flags_t: * @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false. * @HB_SUBSET_FLAGS_NO_HINTING: If set hinting instructions will be dropped in @@ -124,7 +133,7 @@ hb_subset_input_set_user_data (hb_subset_input_t *input, HB_EXTERN void * hb_subset_input_get_user_data (const hb_subset_input_t *input, - hb_user_data_key_t *key); + hb_user_data_key_t *key); HB_EXTERN hb_set_t * hb_subset_input_unicode_set (hb_subset_input_t *input); @@ -145,6 +154,41 @@ hb_subset_input_set_flags (hb_subset_input_t *input, HB_EXTERN hb_face_t * hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input); +HB_EXTERN hb_face_t * +hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan); + +HB_EXTERN hb_subset_plan_t * +hb_subset_plan_create_or_fail (hb_face_t *face, + const hb_subset_input_t *input); + +HB_EXTERN void +hb_subset_plan_destroy (hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan); + + +HB_EXTERN hb_subset_plan_t * +hb_subset_plan_reference (hb_subset_plan_t *plan); + +HB_EXTERN hb_bool_t +hb_subset_plan_set_user_data (hb_subset_plan_t *plan, + hb_user_data_key_t *key, + void *data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +HB_EXTERN void * +hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, + hb_user_data_key_t *key); + + HB_END_DECLS #endif /* HB_SUBSET_H */ diff --git a/thirdparty/harfbuzz/src/hb-uniscribe.cc b/thirdparty/harfbuzz/src/hb-uniscribe.cc index 0e5a114f7d..50f71ce9ce 100644 --- a/thirdparty/harfbuzz/src/hb-uniscribe.cc +++ b/thirdparty/harfbuzz/src/hb-uniscribe.cc @@ -878,7 +878,8 @@ retry: if (backward) hb_buffer_reverse (buffer); - buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); /* Wow, done! */ return true; diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh index b0a1e5e966..7b08e3b4d2 100644 --- a/thirdparty/harfbuzz/src/hb-vector.hh +++ b/thirdparty/harfbuzz/src/hb-vector.hh @@ -29,16 +29,21 @@ #include "hb.hh" #include "hb-array.hh" +#include "hb-meta.hh" #include "hb-null.hh" -template <typename Type> -struct hb_vector_t +template <typename Type, + bool sorted=false> +struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty_t>::type { typedef Type item_t; static constexpr unsigned item_size = hb_static_size (Type); + using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type; + using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type; hb_vector_t () = default; + hb_vector_t (std::nullptr_t) : hb_vector_t () {} hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t () { alloc (lst.size ()); @@ -56,7 +61,8 @@ struct hb_vector_t hb_vector_t (const hb_vector_t &o) : hb_vector_t () { alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return; + copy_vector (o); } hb_vector_t (hb_vector_t &&o) { @@ -67,9 +73,8 @@ struct hb_vector_t } ~hb_vector_t () { fini (); } - private: - int allocated = 0; /* == -1 means allocation failed. */ public: + int allocated = 0; /* == -1 means allocation failed. */ unsigned int length = 0; public: Type *arrayZ = nullptr; @@ -82,16 +87,10 @@ struct hb_vector_t void fini () { + shrink_vector (0); hb_free (arrayZ); init (); } - void fini_deep () - { - unsigned int count = length; - for (unsigned int i = 0; i < count; i++) - arrayZ[i].fini (); - fini (); - } void reset () { @@ -111,7 +110,10 @@ struct hb_vector_t { reset (); alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return *this; + + copy_vector (o); + return *this; } hb_vector_t& operator = (hb_vector_t &&o) @@ -152,24 +154,24 @@ struct hb_vector_t template <typename T> hb_vector_t& operator << (T&& v) { push (std::forward<T> (v)); return *this; } - hb_array_t< Type> as_array () { return hb_array (arrayZ, length); } - hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); } + array_t as_array () { return hb_array (arrayZ, length); } + c_array_t as_array () const { return hb_array (arrayZ, length); } /* Iterator. */ - typedef hb_array_t<const Type> iter_t; - typedef hb_array_t< Type> writer_t; + typedef c_array_t iter_t; + typedef array_t writer_t; iter_t iter () const { return as_array (); } writer_t writer () { return as_array (); } operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const + c_array_t sub_array (unsigned int start_offset, unsigned int count) const { return as_array ().sub_array (start_offset, count); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + c_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) + array_t sub_array (unsigned int start_offset, unsigned int count) { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t<Type> as_sorted_array () @@ -187,9 +189,12 @@ struct hb_vector_t { if (unlikely (!resize (length + 1))) return &Crap (Type); - return &arrayZ[length - 1]; + return std::addressof (arrayZ[length - 1]); } - template <typename T> + template <typename T, + typename T2 = Type, + hb_enable_if (!std::is_copy_constructible<T2>::value && + std::is_copy_assignable<T>::value)> Type *push (T&& v) { Type *p = push (); @@ -201,9 +206,147 @@ struct hb_vector_t *p = std::forward<T> (v); return p; } + template <typename T, + typename T2 = Type, + hb_enable_if (std::is_copy_constructible<T2>::value)> + Type *push (T&& v) + { + if (unlikely (!alloc (length + 1))) + // If push failed to allocate then don't copy v, since this may cause + // the created copy to leak memory since we won't have stored a + // reference to it. + return &Crap (Type); + + /* Emplace. */ + length++; + Type *p = std::addressof (arrayZ[length - 1]); + return new (p) Type (std::forward<T> (v)); + } bool in_error () const { return allocated < 0; } + template <typename T = Type, + hb_enable_if (hb_is_trivially_copy_assignable(T))> + Type * + realloc_vector (unsigned new_allocated) + { + return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copy_assignable(T))> + Type * + realloc_vector (unsigned new_allocated) + { + Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type)); + if (likely (new_array)) + { + for (unsigned i = 0; i < length; i++) + new (std::addressof (new_array[i])) Type (); + for (unsigned i = 0; i < (unsigned) length; i++) + new_array[i] = std::move (arrayZ[i]); + unsigned old_length = length; + shrink_vector (0); + length = old_length; + hb_free (arrayZ); + } + return new_array; + } + + template <typename T = Type, + hb_enable_if (hb_is_trivially_constructible(T))> + void + grow_vector (unsigned size) + { + memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + length = size; + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_constructible(T))> + void + grow_vector (unsigned size) + { + while (length < size) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (); + } + } + + template <typename T = Type, + hb_enable_if (hb_is_trivially_copyable (T))> + void + copy_vector (const hb_vector_t &other) + { + length = other.length; + hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size); + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copyable (T) && + std::is_copy_constructible<T>::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (other.arrayZ[length - 1]); + } + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copyable (T) && + !std::is_copy_constructible<T>::value && + std::is_default_constructible<T>::value && + std::is_copy_assignable<T>::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (); + arrayZ[length - 1] = other.arrayZ[length - 1]; + } + } + + template <typename T = Type, + hb_enable_if (hb_is_trivially_destructible(T))> + void + shrink_vector (unsigned size) + { + length = size; + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_destructible(T))> + void + shrink_vector (unsigned size) + { + while ((unsigned) length > size) + { + arrayZ[(unsigned) length - 1].~Type (); + length--; + } + } + + template <typename T = Type, + hb_enable_if (hb_is_trivially_copy_assignable(T))> + void + shift_down_vector (unsigned i) + { + memmove (static_cast<void *> (&arrayZ[i - 1]), + static_cast<void *> (&arrayZ[i]), + (length - i) * sizeof (Type)); + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copy_assignable(T))> + void + shift_down_vector (unsigned i) + { + for (; i < length; i++) + arrayZ[i - 1] = std::move (arrayZ[i]); + } + /* Allocate for size but don't adjust length. */ bool alloc (unsigned int size) { @@ -225,7 +368,7 @@ struct hb_vector_t (new_allocated < (unsigned) allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); if (likely (!overflows)) - new_array = (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + new_array = realloc_vector (new_allocated); if (unlikely (!new_array)) { @@ -246,7 +389,9 @@ struct hb_vector_t return false; if (size > length) - memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + grow_vector (size); + else if (size < length) + shrink_vector (size); length = size; return true; @@ -255,48 +400,38 @@ struct hb_vector_t Type pop () { if (!length) return Null (Type); - return std::move (arrayZ[--length]); /* Does this move actually work? */ + Type v = arrayZ[length - 1]; + arrayZ[length - 1].~Type (); + length--; + return v; } void remove (unsigned int i) { if (unlikely (i >= length)) return; - memmove (static_cast<void *> (&arrayZ[i]), - static_cast<void *> (&arrayZ[i + 1]), - (length - i - 1) * sizeof (Type)); + shift_down_vector (i + 1); + arrayZ[length - 1].~Type (); length--; } void shrink (int size_) { unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; - if (size < length) - length = size; - } + if (size >= length) + return; - template <typename T> - Type *find (T v) - { - for (unsigned int i = 0; i < length; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; - } - template <typename T> - const Type *find (T v) const - { - for (unsigned int i = 0; i < length; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; + shrink_vector (size); } + + /* Sorting API. */ void qsort (int (*cmp)(const void*, const void*)) { as_array ().qsort (cmp); } void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array ().qsort (start, end); } + /* Unsorted search API. */ template <typename T> Type *lsearch (const T &x, Type *not_found = nullptr) { return as_array ().lsearch (x, not_found); } @@ -306,47 +441,25 @@ struct hb_vector_t template <typename T> bool lfind (const T &x, unsigned *pos = nullptr) const { return as_array ().lfind (x, pos); } -}; - -template <typename Type> -struct hb_sorted_vector_t : hb_vector_t<Type> -{ - hb_sorted_vector_t () = default; - ~hb_sorted_vector_t () = default; - hb_sorted_vector_t (hb_sorted_vector_t& o) = default; - hb_sorted_vector_t (hb_sorted_vector_t &&o) = default; - hb_sorted_vector_t (std::initializer_list<Type> lst) : hb_vector_t<Type> (lst) {} - template <typename Iterable, - hb_requires (hb_is_iterable (Iterable))> - hb_sorted_vector_t (const Iterable &o) : hb_vector_t<Type> (o) {} - hb_sorted_vector_t& operator = (const hb_sorted_vector_t &o) = default; - hb_sorted_vector_t& operator = (hb_sorted_vector_t &&o) = default; - friend void swap (hb_sorted_vector_t& a, hb_sorted_vector_t& b) - { hb_swap ((hb_vector_t<Type>&) (a), (hb_vector_t<Type>&) (b)); } - - hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->length); } - hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); } - - /* Iterator. */ - typedef hb_sorted_array_t<const Type> const_iter_t; - typedef hb_sorted_array_t< Type> iter_t; - const_iter_t iter () const { return as_array (); } - const_iter_t citer () const { return as_array (); } - iter_t iter () { return as_array (); } - operator iter_t () { return iter (); } - operator const_iter_t () const { return iter (); } - template <typename T> + /* Sorted search API. */ + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> Type *bsearch (const T &x, Type *not_found = nullptr) { return as_array ().bsearch (x, not_found); } - template <typename T> + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> const Type *bsearch (const T &x, const Type *not_found = nullptr) const { return as_array ().bsearch (x, not_found); } - template <typename T> + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> bool bfind (const T &x, unsigned int *i = nullptr, hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; +template <typename Type> +using hb_sorted_vector_t = hb_vector_t<Type, true>; + #endif /* HB_VECTOR_HH */ diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h index 52b124b745..ae707cde6c 100644 --- a/thirdparty/harfbuzz/src/hb-version.h +++ b/thirdparty/harfbuzz/src/hb-version.h @@ -41,13 +41,13 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 3 +#define HB_VERSION_MAJOR 4 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 3 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ HB_BEGIN_DECLS * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "3.2.0" +#define HB_VERSION_STRING "4.3.0" /** * HB_VERSION_ATLEAST: diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh index 1f14267525..b9f5f71415 100644 --- a/thirdparty/harfbuzz/src/hb.hh +++ b/thirdparty/harfbuzz/src/hb.hh @@ -447,6 +447,7 @@ static int HB_UNUSED _hb_errno = 0; #ifndef HB_USE_ATEXIT # define HB_USE_ATEXIT 0 #endif +#ifndef hb_atexit #if !HB_USE_ATEXIT # define hb_atexit(_) HB_STMT_START { if (0) (_) (); } HB_STMT_END #else /* HB_USE_ATEXIT */ @@ -457,6 +458,7 @@ static int HB_UNUSED _hb_errno = 0; # define hb_atexit(f) static hb_atexit_t<f> _hb_atexit_##__LINE__; # endif #endif +#endif /* Lets assert int types. Saves trouble down the road. */ static_assert ((sizeof (hb_codepoint_t) == 4), ""); |