summaryrefslogtreecommitdiff
path: root/thirdparty/harfbuzz
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/harfbuzz')
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS.hh165
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh84
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh46
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh58
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh70
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh77
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh14
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh32
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh14
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh35
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh281
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh17
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh113
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh35
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh217
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh35
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh244
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh36
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh227
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh52
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh38
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh420
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh314
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh79
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh79
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh98
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh124
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh140
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh329
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh8
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh258
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/Glyph.hh233
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh48
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh216
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh72
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh90
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf.hh388
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/loca.hh43
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/path-builder.hh135
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh860
-rw-r--r--thirdparty/harfbuzz/src/graph/serialize.hh249
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh62
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh28
-rw-r--r--thirdparty/harfbuzz/src/hb-bimap.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-page.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set-invertible.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set.hh82
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-serialize.cc18
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-verify.cc28
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.cc37
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.h34
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh44
-rw-r--r--thirdparty/harfbuzz/src/hb-cache.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-common.hh118
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh17
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh89
-rw-r--r--thirdparty/harfbuzz/src/hb-common.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-config.hh13
-rw-r--r--thirdparty/harfbuzz/src/hb-coretext.cc56
-rw-r--r--thirdparty/harfbuzz/src/hb-cplusplus.hh192
-rw-r--r--thirdparty/harfbuzz/src/hb-directwrite.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.cc65
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-face.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc181
-rw-r--r--thirdparty/harfbuzz/src/hb-font.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-font.hh81
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc162
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.h9
-rw-r--r--thirdparty/harfbuzz/src/hb-iter.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-map.cc58
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h10
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh167
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh13
-rw-r--r--thirdparty/harfbuzz/src/hb-null.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh182
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.cc45
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.hh170
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.cc38
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.hh30
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh196
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh65
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.cc164
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-glyf-table.hh1328
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh499
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh3090
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh439
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc48
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name-language-static.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name-table.hh36
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh603
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc501
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh431
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh396
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh115
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh492
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh177
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh849
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc44
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh)80
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh)6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh118
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh)141
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-win1256.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh)8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc)27
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.hh)8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-default.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-default.cc)6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc)6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-hebrew.cc)6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh589
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc560
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc)356
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh66
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh428
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc)36
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh553
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc)77
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc)31
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh)13
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc)16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh931
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh)14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc)16
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc)4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.hh)8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex.hh)85
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag-table.hh3565
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc126
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh148
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-priority-queue.hh32
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh1096
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh23
-rw-r--r--thirdparty/harfbuzz/src/hb-set-digest.hh30
-rw-r--r--thirdparty/harfbuzz/src/hb-set.cc20
-rw-r--r--thirdparty/harfbuzz/src/hb-set.h3
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh25
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.cc20
-rw-r--r--thirdparty/harfbuzz/src/hb-shaper.cc16
-rw-r--r--thirdparty/harfbuzz/src/hb-static.cc3
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.hh103
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff1.cc22
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff2.cc28
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.cc15
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc160
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc205
-rw-r--r--thirdparty/harfbuzz/src/hb-ucd-table.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh97
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h6
-rw-r--r--thirdparty/harfbuzz/src/hb.hh5
173 files changed, 14950 insertions, 12815 deletions
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh
new file mode 100644
index 0000000000..224d6b746b
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh
@@ -0,0 +1,165 @@
+#ifndef OT_LAYOUT_GPOS_HH
+#define OT_LAYOUT_GPOS_HH
+
+#include "../../hb-ot-layout-common.hh"
+#include "../../hb-ot-layout-gsubgpos.hh"
+#include "GPOS/Common.hh"
+#include "GPOS/PosLookup.hh"
+
+namespace OT {
+namespace Layout {
+
+static void
+propagate_attachment_offsets (hb_glyph_position_t *pos,
+ unsigned int len,
+ unsigned int i,
+ hb_direction_t direction,
+ unsigned nesting_level = HB_MAX_NESTING_LEVEL);
+
+/*
+ * GPOS -- Glyph Positioning
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
+ */
+
+struct GPOS : GSUBGPOS
+{
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
+
+ using Lookup = GPOS_impl::PosLookup;
+
+ const GPOS_impl::PosLookup& get_lookup (unsigned int i) const
+ { return static_cast<const GPOS_impl::PosLookup &> (GSUBGPOS::get_lookup (i)); }
+
+ static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
+ return GSUBGPOS::subset<GPOS_impl::PosLookup> (&l);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ { return GSUBGPOS::sanitize<GPOS_impl::PosLookup> (c); }
+
+ HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+ hb_face_t *face) const;
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
+ {
+ if (!c->gpos_lookups->has (i)) continue;
+ const GPOS_impl::PosLookup &l = get_lookup (i);
+ l.dispatch (c);
+ }
+ }
+
+ void closure_lookups (hb_face_t *face,
+ const hb_set_t *glyphs,
+ hb_set_t *lookup_indexes /* IN/OUT */) const
+ { GSUBGPOS::closure_lookups<GPOS_impl::PosLookup> (face, glyphs, lookup_indexes); }
+
+ typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
+};
+
+
+static void
+propagate_attachment_offsets (hb_glyph_position_t *pos,
+ unsigned int len,
+ unsigned int i,
+ hb_direction_t direction,
+ unsigned nesting_level)
+{
+ /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+ * offset of glyph they are attached to. */
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain))
+ return;
+
+ pos[i].attach_chain() = 0;
+
+ unsigned int j = (int) i + chain;
+
+ if (unlikely (j >= len))
+ return;
+
+ if (unlikely (!nesting_level))
+ return;
+
+ propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
+
+ assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
+
+ if (type & GPOS_impl::ATTACH_TYPE_CURSIVE)
+ {
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ pos[i].y_offset += pos[j].y_offset;
+ else
+ pos[i].x_offset += pos[j].x_offset;
+ }
+ else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/
+ {
+ pos[i].x_offset += pos[j].x_offset;
+ pos[i].y_offset += pos[j].y_offset;
+
+ assert (j < i);
+ if (HB_DIRECTION_IS_FORWARD (direction))
+ for (unsigned int k = j; k < i; k++) {
+ pos[i].x_offset -= pos[k].x_advance;
+ pos[i].y_offset -= pos[k].y_advance;
+ }
+ else
+ for (unsigned int k = j + 1; k < i + 1; k++) {
+ pos[i].x_offset += pos[k].x_advance;
+ pos[i].y_offset += pos[k].y_advance;
+ }
+ }
+}
+
+void
+GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
+}
+
+void
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
+{
+ //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
+{
+ _hb_buffer_assert_gsubgpos_vars (buffer);
+
+ unsigned int len;
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
+ hb_direction_t direction = buffer->props.direction;
+
+ /* Handle attachments */
+ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
+ 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 : Layout::GPOS::accelerator_t {
+ GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {}
+};
+
+}
+
+#endif /* OT_LAYOUT_GPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh
new file mode 100644
index 0000000000..bfe6b36afd
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh
@@ -0,0 +1,84 @@
+#ifndef OT_LAYOUT_GPOS_ANCHOR_HH
+#define OT_LAYOUT_GPOS_ANCHOR_HH
+
+#include "AnchorFormat1.hh"
+#include "AnchorFormat2.hh"
+#include "AnchorFormat3.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct Anchor
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ AnchorFormat1 format1;
+ AnchorFormat2 format2;
+ AnchorFormat3 format3;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+ case 1: return_trace (u.format1.sanitize (c));
+ case 2: return_trace (u.format2.sanitize (c));
+ case 3: return_trace (u.format3.sanitize (c));
+ default:return_trace (true);
+ }
+ }
+
+ void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+ float *x, float *y) const
+ {
+ *x = *y = 0;
+ switch (u.format) {
+ case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+ case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+ case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
+ default: return;
+ }
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ switch (u.format) {
+ case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+ case 2:
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ // AnchorFormat 2 just containins extra hinting information, so
+ // if hints are being dropped convert to format 1.
+ return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+ }
+ return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
+ case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
+ c->plan->layout_variation_idx_map))));
+ default:return_trace (false);
+ }
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ switch (u.format) {
+ case 1: case 2:
+ return;
+ case 3:
+ u.format3.collect_variation_indices (c);
+ return;
+ default: return;
+ }
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_ANCHOR_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh
new file mode 100644
index 0000000000..738cc31bbf
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh
@@ -0,0 +1,46 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ FWORD xCoordinate; /* Horizontal value--in design units */
+ FWORD yCoordinate; /* Vertical value--in design units */
+ public:
+ DEFINE_SIZE_STATIC (6);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+ float *x, float *y) const
+ {
+ hb_font_t *font = c->font;
+ *x = font->em_fscale_x (xCoordinate);
+ *y = font->em_fscale_y (yCoordinate);
+ }
+
+ AnchorFormat1* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ AnchorFormat1* out = c->embed<AnchorFormat1> (this);
+ if (!out) return_trace (out);
+ out->format = 1;
+ return_trace (out);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh
new file mode 100644
index 0000000000..70b4d19f53
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh
@@ -0,0 +1,58 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat2
+{
+
+ protected:
+ HBUINT16 format; /* Format identifier--format = 2 */
+ FWORD xCoordinate; /* Horizontal value--in design units */
+ FWORD yCoordinate; /* Vertical value--in design units */
+ HBUINT16 anchorPoint; /* Index to glyph contour point */
+ public:
+ DEFINE_SIZE_STATIC (8);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+ float *x, float *y) const
+ {
+ hb_font_t *font = c->font;
+
+#ifdef HB_NO_HINTING
+ *x = font->em_fscale_x (xCoordinate);
+ *y = font->em_fscale_y (yCoordinate);
+ return;
+#endif
+
+ unsigned int x_ppem = font->x_ppem;
+ unsigned int y_ppem = font->y_ppem;
+ hb_position_t cx = 0, cy = 0;
+ bool ret;
+
+ ret = (x_ppem || y_ppem) &&
+ font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+ *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
+ *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
+ }
+
+ AnchorFormat2* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (c->embed<AnchorFormat2> (this));
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
new file mode 100644
index 0000000000..d77b4699be
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -0,0 +1,70 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat3
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 3 */
+ FWORD xCoordinate; /* Horizontal value--in design units */
+ FWORD yCoordinate; /* Vertical value--in design units */
+ Offset16To<Device>
+ xDeviceTable; /* Offset to Device table for X
+ * coordinate-- from beginning of
+ * Anchor table (may be NULL) */
+ Offset16To<Device>
+ yDeviceTable; /* Offset to Device table for Y
+ * coordinate-- from beginning of
+ * Anchor table (may be NULL) */
+ public:
+ DEFINE_SIZE_STATIC (10);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+ }
+
+ void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+ float *x, float *y) const
+ {
+ hb_font_t *font = c->font;
+ *x = font->em_fscale_x (xCoordinate);
+ *y = font->em_fscale_y (yCoordinate);
+
+ if (font->x_ppem || font->num_coords)
+ *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
+ if (font->y_ppem || font->num_coords)
+ *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
+ }
+
+ AnchorFormat3* copy (hb_serialize_context_t *c,
+ const hb_map_t *layout_variation_idx_map) const
+ {
+ TRACE_SERIALIZE (this);
+ if (!layout_variation_idx_map) return_trace (nullptr);
+
+ auto *out = c->embed<AnchorFormat3> (this);
+ if (unlikely (!out)) return_trace (nullptr);
+
+ out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+ out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+ return_trace (out);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
+ (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh
new file mode 100644
index 0000000000..c442efa1ea
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -0,0 +1,77 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+#define OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorMatrix
+{
+ HBUINT16 rows; /* Number of rows */
+ UnsizedArrayOf<Offset16To<Anchor>>
+ matrixZ; /* Matrix of offsets to Anchor tables--
+ * from beginning of AnchorMatrix table */
+ public:
+ DEFINE_SIZE_ARRAY (2, matrixZ);
+
+ bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+ {
+ TRACE_SANITIZE (this);
+ if (!c->check_struct (this)) return_trace (false);
+ if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
+ unsigned int count = rows * cols;
+ if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+ for (unsigned int i = 0; i < count; i++)
+ if (!matrixZ[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ const Anchor& get_anchor (unsigned int row, unsigned int col,
+ unsigned int cols, bool *found) const
+ {
+ *found = false;
+ if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
+ *found = !matrixZ[row * cols + col].is_null ();
+ return this+matrixZ[row * cols + col];
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ Iterator index_iter) const
+ {
+ for (unsigned i : index_iter)
+ (this+matrixZ[i]).collect_variation_indices (c);
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ unsigned num_rows,
+ Iterator index_iter) const
+ {
+ TRACE_SUBSET (this);
+
+ auto *out = c->serializer->start_embed (this);
+
+ if (!index_iter) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ out->rows = num_rows;
+ for (const unsigned i : index_iter)
+ {
+ auto *offset = c->serializer->embed (matrixZ[i]);
+ if (!offset) return_trace (false);
+ offset->serialize_subset (c, matrixZ[i], this);
+ }
+
+ return_trace (true);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_ANCHORMATRIX_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh
new file mode 100644
index 0000000000..d551ac2a2b
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ChainContextPos : ChainContext {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh
new file mode 100644
index 0000000000..e16c06729d
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh
@@ -0,0 +1,32 @@
+#ifndef OT_LAYOUT_GPOS_COMMON_HH
+#define OT_LAYOUT_GPOS_COMMON_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+enum attach_type_t {
+ ATTACH_TYPE_NONE = 0X00,
+
+ /* Each attachment should be either a mark or a cursive; can't be both. */
+ ATTACH_TYPE_MARK = 0X01,
+ ATTACH_TYPE_CURSIVE = 0X02,
+};
+
+/* buffer **position** var allocations */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+template<typename Iterator, typename SrcLookup>
+static void SinglePos_serialize (hb_serialize_context_t *c,
+ const SrcLookup *src,
+ Iterator it,
+ const hb_map_t *layout_variation_idx_map);
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_COMMON_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh
new file mode 100644
index 0000000000..2a01eaa3a6
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ContextPos : Context {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CONTEXTPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh
new file mode 100644
index 0000000000..c105cfb091
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOS_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOS_HH
+
+#include "CursivePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct CursivePos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ CursivePosFormat1 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 /* OT_LAYOUT_GPOS_CURSIVEPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
new file mode 100644
index 0000000000..e212fab976
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -0,0 +1,281 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+
+#include "Anchor.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct EntryExitRecord
+{
+ friend struct CursivePosFormat1;
+
+ bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ const void *src_base) const
+ {
+ (src_base+entryAnchor).collect_variation_indices (c);
+ (src_base+exitAnchor).collect_variation_indices (c);
+ }
+
+ EntryExitRecord* subset (hb_subset_context_t *c,
+ const void *src_base) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (nullptr);
+
+ out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+ out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+ return_trace (out);
+ }
+
+ protected:
+ Offset16To<Anchor>
+ entryAnchor; /* Offset to EntryAnchor table--from
+ * beginning of CursivePos
+ * subtable--may be NULL */
+ Offset16To<Anchor>
+ exitAnchor; /* Offset to ExitAnchor table--from
+ * beginning of CursivePos
+ * subtable--may be NULL */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) {
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
+ return;
+
+ pos[i].attach_chain() = 0;
+
+ unsigned int j = (int) i + chain;
+
+ /* Stop if we see new parent in the chain. */
+ if (j == new_parent)
+ return;
+
+ reverse_cursive_minor_offset (pos, j, direction, new_parent);
+
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ pos[j].y_offset = -pos[i].y_offset;
+ else
+ pos[j].x_offset = -pos[i].x_offset;
+
+ pos[j].attach_chain() = -chain;
+ pos[j].attach_type() = type;
+}
+
+
+struct CursivePosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ Array16Of<EntryExitRecord>
+ entryExitRecord; /* Array of EntryExit records--in
+ * Coverage Index order */
+ public:
+ DEFINE_SIZE_ARRAY (6, entryExitRecord);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ + hb_zip (this+coverage, entryExitRecord)
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
+ ;
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+
+ const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
+ if (!this_record.entryAnchor) return_trace (false);
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ 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)
+ {
+ 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;
+
+ buffer->unsafe_to_break (i, j);
+ float entry_x, entry_y, exit_x, exit_y;
+ (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+ (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
+
+ hb_glyph_position_t *pos = buffer->pos;
+
+ hb_position_t d;
+ /* Main-direction adjustment */
+ switch (c->direction) {
+ case HB_DIRECTION_LTR:
+ pos[i].x_advance = roundf (exit_x) + pos[i].x_offset;
+
+ d = roundf (entry_x) + pos[j].x_offset;
+ pos[j].x_advance -= d;
+ pos[j].x_offset -= d;
+ break;
+ case HB_DIRECTION_RTL:
+ d = roundf (exit_x) + pos[i].x_offset;
+ pos[i].x_advance -= d;
+ pos[i].x_offset -= d;
+
+ pos[j].x_advance = roundf (entry_x) + pos[j].x_offset;
+ break;
+ case HB_DIRECTION_TTB:
+ pos[i].y_advance = roundf (exit_y) + pos[i].y_offset;
+
+ d = roundf (entry_y) + pos[j].y_offset;
+ pos[j].y_advance -= d;
+ pos[j].y_offset -= d;
+ break;
+ case HB_DIRECTION_BTT:
+ d = roundf (exit_y) + pos[i].y_offset;
+ pos[i].y_advance -= d;
+ pos[i].y_offset -= d;
+
+ pos[j].y_advance = roundf (entry_y);
+ break;
+ case HB_DIRECTION_INVALID:
+ default:
+ break;
+ }
+
+ /* Cross-direction adjustment */
+
+ /* We attach child to parent (think graph theory and rooted trees whereas
+ * the root stays on baseline and each node aligns itself against its
+ * parent.
+ *
+ * Optimize things for the case of RightToLeft, as that's most common in
+ * Arabic. */
+ unsigned int child = i;
+ unsigned int parent = j;
+ hb_position_t x_offset = entry_x - exit_x;
+ hb_position_t y_offset = entry_y - exit_y;
+ if (!(c->lookup_props & LookupFlag::RightToLeft))
+ {
+ unsigned int k = child;
+ child = parent;
+ parent = k;
+ x_offset = -x_offset;
+ y_offset = -y_offset;
+ }
+
+ /* If child was already connected to someone else, walk through its old
+ * chain and reverse the link direction, such that the whole tree of its
+ * previous connection now attaches to new parent. Watch out for case
+ * where new parent is on the path from old chain...
+ */
+ reverse_cursive_minor_offset (pos, child, c->direction, parent);
+
+ pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+ pos[child].attach_chain() = (int) parent - (int) child;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+ pos[child].y_offset = y_offset;
+ else
+ pos[child].x_offset = x_offset;
+
+ /* If parent was attached to child, separate them.
+ * https://github.com/harfbuzz/harfbuzz/issues/2469
+ */
+ if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+ pos[parent].attach_chain() = 0;
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_subset_context_t *c,
+ Iterator it,
+ const void *src_base)
+ {
+ if (unlikely (!c->serializer->extend_min ((*this)))) return;
+ this->format = 1;
+ this->entryExitRecord.len = it.len ();
+
+ for (const EntryExitRecord& entry_record : + it
+ | hb_map (hb_second))
+ entry_record.subset (c, src_base);
+
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ coverage.serialize_serialize (c->serializer, 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 (!out)) return_trace (false);
+
+ auto it =
+ + hb_zip (this+coverage, entryExitRecord)
+ | hb_filter (glyphset, hb_first)
+ | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
+ { return hb_pair (glyph_map[p.first], p.second);})
+ ;
+
+ bool ret = bool (it);
+ out->serialize (c, it, this);
+ return_trace (ret);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh
new file mode 100644
index 0000000000..d1808adab4
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh
@@ -0,0 +1,17 @@
+#ifndef OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+#define OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ExtensionPos : Extension<ExtensionPos>
+{
+ typedef struct PosLookupSubTable SubTable;
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_EXTENSIONPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
new file mode 100644
index 0000000000..f8cddd1991
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
@@ -0,0 +1,113 @@
+#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
+#define OT_LAYOUT_GPOS_MARKARRAY_HH
+
+#include "AnchorMatrix.hh"
+#include "MarkRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */
+{
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (Array16Of<MarkRecord>::sanitize (c, this));
+ }
+
+ bool apply (hb_ot_apply_context_t *c,
+ unsigned int mark_index, unsigned int glyph_index,
+ const AnchorMatrix &anchors, unsigned int class_count,
+ unsigned int glyph_pos) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
+ unsigned int mark_class = record.klass;
+
+ const Anchor& mark_anchor = this + record.markAnchor;
+ bool found;
+ const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ /* If this subtable doesn't have an anchor for this base and this class,
+ * return false such that the subsequent subtables have a chance at it. */
+ if (unlikely (!found)) return_trace (false);
+
+ float mark_x, mark_y, base_x, base_y;
+
+ 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);
+
+ hb_glyph_position_t &o = buffer->cur_pos();
+ o.x_offset = roundf (base_x - mark_x);
+ o.y_offset = roundf (base_y - mark_y);
+ o.attach_type() = ATTACH_TYPE_MARK;
+ o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ Iterator coverage,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+ auto* out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ auto mark_iter =
+ + hb_zip (coverage, this->iter ())
+ | hb_filter (glyphset, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ unsigned new_length = 0;
+ for (const auto& mark_record : mark_iter) {
+ if (unlikely (!mark_record.subset (c, this, klass_mapping)))
+ return_trace (false);
+ new_length++;
+ }
+
+ if (unlikely (!c->serializer->check_assign (out->len, new_length,
+ HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
+ return_trace (false);
+
+ return_trace (true);
+ }
+};
+
+static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
+ const MarkArray &mark_array,
+ const hb_set_t &glyphset,
+ hb_map_t* klass_mapping /* INOUT */)
+{
+ hb_set_t orig_classes;
+
+ + hb_zip (mark_coverage, mark_array)
+ | hb_filter (glyphset, hb_first)
+ | hb_map (hb_second)
+ | hb_map (&MarkRecord::get_class)
+ | hb_sink (orig_classes)
+ ;
+
+ unsigned idx = 0;
+ for (auto klass : orig_classes.iter ())
+ {
+ if (klass_mapping->has (klass)) continue;
+ klass_mapping->set (klass, idx);
+ idx++;
+ }
+}
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
new file mode 100644
index 0000000000..e99e13ff84
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOS_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOS_HH
+
+#include "MarkBasePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkBasePos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ MarkBasePosFormat1 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 /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
new file mode 100644
index 0000000000..a10b806fe5
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -0,0 +1,217 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+
+#include "MarkArray.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix BaseArray; /* base-major--
+ * in order of BaseCoverage Index--,
+ * mark-minor--
+ * ordered by class--zero-based. */
+
+struct MarkBasePosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ markCoverage; /* Offset to MarkCoverage table--from
+ * beginning of MarkBasePos subtable */
+ Offset16To<Coverage>
+ baseCoverage; /* Offset to BaseCoverage table--from
+ * beginning of MarkBasePos subtable */
+ HBUINT16 classCount; /* Number of classes defined for marks */
+ Offset16To<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkBasePos subtable */
+ Offset16To<BaseArray>
+ baseArray; /* Offset to BaseArray table--from
+ * beginning of MarkBasePos subtable */
+
+ public:
+ DEFINE_SIZE_STATIC (12);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ markCoverage.sanitize (c, this) &&
+ baseCoverage.sanitize (c, this) &&
+ markArray.sanitize (c, this) &&
+ baseArray.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return (this+markCoverage).intersects (glyphs) &&
+ (this+baseCoverage).intersects (glyphs);
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+ ;
+
+ hb_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+ unsigned basecount = (this+baseArray).rows;
+ auto base_iter =
+ + hb_zip (this+baseCoverage, hb_range (basecount))
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ hb_sorted_vector_t<unsigned> base_indexes;
+ for (const unsigned row : base_iter)
+ {
+ + hb_range ((unsigned) classCount)
+ | hb_filter (klass_mapping)
+ | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+ | hb_sink (base_indexes)
+ ;
+ }
+ (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+ if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
+ }
+
+ const Coverage &get_coverage () const { return this+markCoverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
+ if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+ /* Now we search backwards for a non-mark glyph */
+ 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);
+ do {
+ 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...
+ * ...but stop if we find a mark in the MultipleSubst sequence:
+ * https://github.com/harfbuzz/harfbuzz/issues/1020 */
+ if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
+ 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
+ (skippy_iter.idx == 0 ||
+ _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
+ _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
+ _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
+ _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
+ _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
+ ))
+ break;
+ skippy_iter.reject ();
+ } while (true);
+
+ /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+ //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)
+ {
+ 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));
+ }
+
+ 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_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+ if (!klass_mapping.get_population ()) return_trace (false);
+ out->classCount = klass_mapping.get_population ();
+
+ auto mark_iter =
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ + mark_iter
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+
+ if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+ return_trace (false);
+
+ out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping);
+
+ unsigned basecount = (this+baseArray).rows;
+ auto base_iter =
+ + hb_zip (this+baseCoverage, hb_range (basecount))
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ new_coverage.reset ();
+ + base_iter
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+
+ if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+ return_trace (false);
+
+ hb_sorted_vector_t<unsigned> base_indexes;
+ for (const unsigned row : + base_iter
+ | hb_map (hb_second))
+ {
+ + hb_range ((unsigned) classCount)
+ | hb_filter (klass_mapping)
+ | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+ | hb_sink (base_indexes)
+ ;
+ }
+
+ out->baseArray.serialize_subset (c, baseArray, this,
+ base_iter.len (),
+ base_indexes.iter ());
+
+ return_trace (true);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
new file mode 100644
index 0000000000..7e74aa73e0
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOS_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOS_HH
+
+#include "MarkLigPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkLigPos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ MarkLigPosFormat1 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 /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
new file mode 100644
index 0000000000..4382aa6c6c
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -0,0 +1,244 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix LigatureAttach; /* component-major--
+ * in order of writing direction--,
+ * mark-minor--
+ * ordered by class--zero-based. */
+
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : List16OfOffset16To<LigatureAttach>
+{
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ Iterator coverage,
+ unsigned class_count,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ for (const auto _ : + hb_zip (coverage, *this)
+ | hb_filter (glyphset, hb_first))
+ {
+ auto *matrix = out->serialize_append (c->serializer);
+ if (unlikely (!matrix)) return_trace (false);
+
+ const LigatureAttach& src = (this + _.second);
+ auto indexes =
+ + hb_range (src.rows * class_count)
+ | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
+ ;
+ matrix->serialize_subset (c,
+ _.second,
+ this,
+ src.rows,
+ indexes);
+ }
+ return_trace (this->len);
+ }
+};
+
+struct MarkLigPosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ markCoverage; /* Offset to Mark Coverage table--from
+ * beginning of MarkLigPos subtable */
+ Offset16To<Coverage>
+ ligatureCoverage; /* Offset to Ligature Coverage
+ * table--from beginning of MarkLigPos
+ * subtable */
+ HBUINT16 classCount; /* Number of defined mark classes */
+ Offset16To<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkLigPos subtable */
+ Offset16To<LigatureArray>
+ ligatureArray; /* Offset to LigatureArray table--from
+ * beginning of MarkLigPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (12);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ markCoverage.sanitize (c, this) &&
+ ligatureCoverage.sanitize (c, this) &&
+ markArray.sanitize (c, this) &&
+ ligatureArray.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return (this+markCoverage).intersects (glyphs) &&
+ (this+ligatureCoverage).intersects (glyphs);
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+ ;
+
+ hb_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+ unsigned ligcount = (this+ligatureArray).len;
+ auto lig_iter =
+ + hb_zip (this+ligatureCoverage, hb_range (ligcount))
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ const LigatureArray& lig_array = this+ligatureArray;
+ for (const unsigned i : lig_iter)
+ {
+ hb_sorted_vector_t<unsigned> lig_indexes;
+ unsigned row_count = lig_array[i].rows;
+ for (unsigned row : + hb_range (row_count))
+ {
+ + hb_range ((unsigned) classCount)
+ | hb_filter (klass_mapping)
+ | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+ | hb_sink (lig_indexes)
+ ;
+ }
+
+ lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
+ }
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+ if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
+ }
+
+ const Coverage &get_coverage () const { return this+markCoverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
+ if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+ /* Now we search backwards for a non-mark glyph */
+ 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);
+ 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)
+ {
+ 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))
+ {
+ 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
+ * can directly use the component index. If not, we attach the mark
+ * glyph to the last component of the ligature. */
+ unsigned int comp_index;
+ unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+ if (lig_id && lig_id == mark_id && mark_comp > 0)
+ comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+ else
+ comp_index = comp_count - 1;
+
+ return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+ }
+
+ 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_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+ if (!klass_mapping.get_population ()) return_trace (false);
+ out->classCount = klass_mapping.get_population ();
+
+ auto mark_iter =
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ auto new_mark_coverage =
+ + mark_iter
+ | hb_map_retains_sorting (hb_first)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
+ return_trace (false);
+
+ out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping);
+
+ auto new_ligature_coverage =
+ + hb_iter (this + ligatureCoverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
+ return_trace (false);
+
+ out->ligatureArray.serialize_subset (c, ligatureArray, this,
+ hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
+
+ return_trace (true);
+ }
+
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
new file mode 100644
index 0000000000..c0eee6d54c
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
@@ -0,0 +1,36 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOS_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOS_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkMarkPos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ MarkMarkPosFormat1 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 /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
new file mode 100644
index 0000000000..c48a74f773
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -0,0 +1,227 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix Mark2Array; /* mark2-major--
+ * in order of Mark2Coverage Index--,
+ * mark1-minor--
+ * ordered by class--zero-based. */
+
+struct MarkMarkPosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ mark1Coverage; /* Offset to Combining Mark1 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ Offset16To<Coverage>
+ mark2Coverage; /* Offset to Combining Mark2 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ HBUINT16 classCount; /* Number of defined mark classes */
+ Offset16To<MarkArray>
+ mark1Array; /* Offset to Mark1Array table--from
+ * beginning of MarkMarkPos subtable */
+ Offset16To<Mark2Array>
+ mark2Array; /* Offset to Mark2Array table--from
+ * beginning of MarkMarkPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (12);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mark1Coverage.sanitize (c, this) &&
+ mark2Coverage.sanitize (c, this) &&
+ mark1Array.sanitize (c, this) &&
+ mark2Array.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return (this+mark1Coverage).intersects (glyphs) &&
+ (this+mark2Coverage).intersects (glyphs);
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ + hb_zip (this+mark1Coverage, this+mark1Array)
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
+ ;
+
+ hb_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
+
+ unsigned mark2_count = (this+mark2Array).rows;
+ auto mark2_iter =
+ + hb_zip (this+mark2Coverage, hb_range (mark2_count))
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ hb_sorted_vector_t<unsigned> mark2_indexes;
+ for (const unsigned row : mark2_iter)
+ {
+ + hb_range ((unsigned) classCount)
+ | hb_filter (klass_mapping)
+ | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+ | hb_sink (mark2_indexes)
+ ;
+ }
+ (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
+ if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
+ }
+
+ const Coverage &get_coverage () const { return this+mark1Coverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
+ if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+
+ /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+ 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);
+ 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]))
+ {
+ buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+ return_trace (false);
+ }
+
+ unsigned int j = skippy_iter.idx;
+
+ unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+ unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
+
+ if (likely (id1 == id2))
+ {
+ if (id1 == 0) /* Marks belonging to the same base. */
+ goto good;
+ else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
+ goto good;
+ }
+ else
+ {
+ /* If ligature ids don't match, it may be the case that one of the marks
+ * itself is a ligature. In which case match. */
+ if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
+ goto good;
+ }
+
+ /* 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)
+ {
+ 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));
+ }
+
+ 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_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
+
+ if (!klass_mapping.get_population ()) return_trace (false);
+ out->classCount = klass_mapping.get_population ();
+
+ auto mark1_iter =
+ + hb_zip (this+mark1Coverage, this+mark1Array)
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ + mark1_iter
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+
+ if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+ return_trace (false);
+
+ out->mark1Array.serialize_subset (c, mark1Array, this,
+ (this+mark1Coverage).iter (),
+ &klass_mapping);
+
+ unsigned mark2count = (this+mark2Array).rows;
+ auto mark2_iter =
+ + hb_zip (this+mark2Coverage, hb_range (mark2count))
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ new_coverage.reset ();
+ + mark2_iter
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+
+ if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+ return_trace (false);
+
+ hb_sorted_vector_t<unsigned> mark2_indexes;
+ for (const unsigned row : + mark2_iter
+ | hb_map (hb_second))
+ {
+ + hb_range ((unsigned) classCount)
+ | hb_filter (klass_mapping)
+ | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+ | hb_sink (mark2_indexes)
+ ;
+ }
+
+ out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
+
+ return_trace (true);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh
new file mode 100644
index 0000000000..7a514453ae
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh
@@ -0,0 +1,52 @@
+#ifndef OT_LAYOUT_GPOS_MARKRECORD_HH
+#define OT_LAYOUT_GPOS_MARKRECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkRecord
+{
+ friend struct MarkArray;
+
+ protected:
+ HBUINT16 klass; /* Class defined for this mark */
+ Offset16To<Anchor>
+ markAnchor; /* Offset to Anchor table--from
+ * beginning of MarkArray table */
+ public:
+ DEFINE_SIZE_STATIC (4);
+
+ unsigned get_class () const { return (unsigned) klass; }
+ bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+ }
+
+ MarkRecord *subset (hb_subset_context_t *c,
+ const void *src_base,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (nullptr);
+
+ out->klass = klass_mapping->get (klass);
+ out->markAnchor.serialize_subset (c, markAnchor, src_base);
+ return_trace (out);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ const void *src_base) const
+ {
+ (src_base+markAnchor).collect_variation_indices (c);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKRECORD_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
new file mode 100644
index 0000000000..8479178d38
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
@@ -0,0 +1,38 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOS_HH
+#define OT_LAYOUT_GPOS_PAIRPOS_HH
+
+#include "PairPosFormat1.hh"
+#include "PairPosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairPos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ PairPosFormat1 format1;
+ PairPosFormat2 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 ());
+ }
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOS_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
new file mode 100644
index 0000000000..35a2db2d45
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -0,0 +1,420 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairValueRecord
+{
+ friend struct PairSet;
+
+ int cmp (hb_codepoint_t k) const
+ { return secondGlyph.cmp (k); }
+
+ struct context_t
+ {
+ const void *base;
+ const ValueFormat *valueFormats;
+ const ValueFormat *newFormats;
+ unsigned len1; /* valueFormats[0].get_len() */
+ const hb_map_t *glyph_map;
+ const hb_map_t *layout_variation_idx_map;
+ };
+
+ bool subset (hb_subset_context_t *c,
+ context_t *closure) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *s = c->serializer;
+ auto *out = s->start_embed (*this);
+ if (unlikely (!s->extend_min (out))) return_trace (false);
+
+ out->secondGlyph = (*closure->glyph_map)[secondGlyph];
+
+ closure->valueFormats[0].copy_values (s,
+ closure->newFormats[0],
+ closure->base, &values[0],
+ closure->layout_variation_idx_map);
+ closure->valueFormats[1].copy_values (s,
+ closure->newFormats[1],
+ closure->base,
+ &values[closure->len1],
+ closure->layout_variation_idx_map);
+
+ return_trace (true);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ const ValueFormat *valueFormats,
+ const void *base) const
+ {
+ unsigned record1_len = valueFormats[0].get_len ();
+ unsigned record2_len = valueFormats[1].get_len ();
+ const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
+
+ if (valueFormats[0].has_device ())
+ valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
+
+ if (valueFormats[1].has_device ())
+ valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
+ }
+
+ bool intersects (const hb_set_t& glyphset) const
+ {
+ return glyphset.has(secondGlyph);
+ }
+
+ const Value* get_values_1 () const
+ {
+ return &values[0];
+ }
+
+ const Value* get_values_2 (ValueFormat format1) const
+ {
+ return &values[format1.get_len ()];
+ }
+
+ protected:
+ HBGlyphID16 secondGlyph; /* GlyphID of second glyph in the
+ * pair--first glyph is listed in the
+ * Coverage table */
+ ValueRecord values; /* Positioning data for the first glyph
+ * followed by for second glyph */
+ public:
+ DEFINE_SIZE_ARRAY (2, values);
+};
+
+struct PairSet
+{
+ friend struct PairPosFormat1;
+
+ bool intersects (const hb_set_t *glyphs,
+ const ValueFormat *valueFormats) const
+ {
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = &firstPairValueRecord;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (glyphs->has (record->secondGlyph))
+ return true;
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+ return false;
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c,
+ const ValueFormat *valueFormats) const
+ {
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = &firstPairValueRecord;
+ c->input->add_array (&record->secondGlyph, len, record_size);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ const ValueFormat *valueFormats) const
+ {
+ unsigned len1 = valueFormats[0].get_len ();
+ unsigned len2 = valueFormats[1].get_len ();
+ unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = &firstPairValueRecord;
+ unsigned count = len;
+ for (unsigned i = 0; i < count; i++)
+ {
+ if (c->glyph_set->has (record->secondGlyph))
+ { record->collect_variation_indices (c, valueFormats, this); }
+
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+ }
+
+ bool apply (hb_ot_apply_context_t *c,
+ const ValueFormat *valueFormats,
+ unsigned int pos) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+ &firstPairValueRecord,
+ len,
+ record_size);
+ if (record)
+ {
+ bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+ bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+ if (applied_first || applied_second)
+ buffer->unsafe_to_break (buffer->idx, pos + 1);
+ if (len2)
+ pos++;
+ buffer->idx = pos;
+ return_trace (true);
+ }
+ buffer->unsafe_to_concat (buffer->idx, pos + 1);
+ return_trace (false);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const ValueFormat valueFormats[2],
+ const ValueFormat newFormats[2]) const
+ {
+ TRACE_SUBSET (this);
+ auto snap = c->serializer->snapshot ();
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->len = 0;
+
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ unsigned len1 = valueFormats[0].get_len ();
+ unsigned len2 = valueFormats[1].get_len ();
+ unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+ PairValueRecord::context_t context =
+ {
+ this,
+ valueFormats,
+ newFormats,
+ len1,
+ &glyph_map,
+ c->plan->layout_variation_idx_map
+ };
+
+ const PairValueRecord *record = &firstPairValueRecord;
+ unsigned count = len, num = 0;
+ for (unsigned i = 0; i < count; i++)
+ {
+ if (glyphset.has (record->secondGlyph)
+ && record->subset (c, &context)) num++;
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+
+ out->len = num;
+ if (!num) c->serializer->revert (snap);
+ return_trace (num);
+ }
+
+ struct sanitize_closure_t
+ {
+ const ValueFormat *valueFormats;
+ unsigned int len1; /* valueFormats[0].get_len() */
+ unsigned int stride; /* 1 + len1 + len2 */
+ };
+
+ bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+ {
+ TRACE_SANITIZE (this);
+ if (!(c->check_struct (this)
+ && c->check_range (&firstPairValueRecord,
+ len,
+ HBUINT16::static_size,
+ closure->stride))) return_trace (false);
+
+ unsigned int count = len;
+ const PairValueRecord *record = &firstPairValueRecord;
+ return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+ closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+ }
+
+ protected:
+ HBUINT16 len; /* Number of PairValueRecords */
+ PairValueRecord firstPairValueRecord;
+ /* Array of PairValueRecords--ordered
+ * by GlyphID of the second glyph */
+ public:
+ DEFINE_SIZE_MIN (2);
+};
+
+struct PairPosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat[2]; /* [0] Defines the types of data in
+ * ValueRecord1--for the first glyph
+ * in the pair--may be zero (0) */
+ /* [1] Defines the types of data in
+ * ValueRecord2--for the second glyph
+ * in the pair--may be zero (0) */
+ Array16OfOffset16To<PairSet>
+ pairSet; /* Array of PairSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (10, pairSet);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+
+ if (!c->check_struct (this)) return_trace (false);
+
+ unsigned int len1 = valueFormat[0].get_len ();
+ unsigned int len2 = valueFormat[1].get_len ();
+ PairSet::sanitize_closure_t closure =
+ {
+ valueFormat,
+ len1,
+ 1 + len1 + len2
+ };
+
+ return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+ }
+
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return
+ + hb_zip (this+coverage, pairSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second)
+ | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
+ { return (this+_).intersects (glyphs, valueFormat); })
+ | hb_any
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
+
+ auto it =
+ + hb_zip (this+coverage, pairSet)
+ | hb_filter (c->glyph_set, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ if (!it) return;
+ + it
+ | hb_map (hb_add (this))
+ | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
+ ;
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ unsigned int count = pairSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+pairSet[i]).collect_glyphs (c, valueFormat);
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ 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));
+ }
+
+ 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;
+ out->valueFormat[0] = valueFormat[0];
+ out->valueFormat[1] = valueFormat[1];
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
+ out->valueFormat[0] = newFormats.first;
+ out->valueFormat[1] = newFormats.second;
+ }
+
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+
+ + hb_zip (this+coverage, pairSet)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
+ {
+ auto snap = c->serializer->snapshot ();
+ auto *o = out->pairSet.serialize_append (c->serializer);
+ if (unlikely (!o)) return false;
+ bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
+ if (!ret)
+ {
+ out->pairSet.pop ();
+ c->serializer->revert (snap);
+ }
+ return ret;
+ },
+ 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));
+ }
+
+
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+ {
+ unsigned len1 = valueFormat[0].get_len ();
+ unsigned len2 = valueFormat[1].get_len ();
+ unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+ unsigned format1 = 0;
+ unsigned format2 = 0;
+ for (const Offset16To<PairSet>& _ :
+ + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
+ {
+ const PairSet& set = (this + _);
+ const PairValueRecord *record = &set.firstPairValueRecord;
+
+ for (unsigned i = 0; i < set.len; i++)
+ {
+ if (record->intersects (glyphset))
+ {
+ format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
+ format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+ }
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+ }
+
+ return hb_pair (format1, format2);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
new file mode 100644
index 0000000000..3f5f9959c4
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -0,0 +1,314 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairPosFormat2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 2 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat1; /* ValueRecord definition--for the
+ * first glyph of the pair--may be zero
+ * (0) */
+ ValueFormat valueFormat2; /* ValueRecord definition--for the
+ * second glyph of the pair--may be
+ * zero (0) */
+ Offset16To<ClassDef>
+ classDef1; /* Offset to ClassDef table--from
+ * beginning of PairPos subtable--for
+ * the first glyph of the pair */
+ Offset16To<ClassDef>
+ classDef2; /* Offset to ClassDef table--from
+ * beginning of PairPos subtable--for
+ * the second glyph of the pair */
+ HBUINT16 class1Count; /* Number of classes in ClassDef1
+ * table--includes Class0 */
+ HBUINT16 class2Count; /* Number of classes in ClassDef2
+ * table--includes Class0 */
+ ValueRecord values; /* Matrix of value pairs:
+ * class1-major, class2-minor,
+ * Each entry has value1 and value2 */
+ public:
+ DEFINE_SIZE_ARRAY (16, values);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!(c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && classDef1.sanitize (c, this)
+ && classDef2.sanitize (c, this))) return_trace (false);
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int stride = len1 + len2;
+ unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
+ unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+ return_trace (c->check_range ((const void *) values,
+ count,
+ record_size) &&
+ valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return (this+coverage).intersects (glyphs) &&
+ (this+classDef2).intersects (glyphs);
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ if (!intersects (c->glyph_set)) return;
+ if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
+
+ hb_set_t klass1_glyphs, klass2_glyphs;
+ if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
+ if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
+
+ hb_set_t class1_set, class2_set;
+ for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
+ {
+ if (!klass1_glyphs.has (cp)) class1_set.add (0);
+ else
+ {
+ unsigned klass1 = (this+classDef1).get (cp);
+ class1_set.add (klass1);
+ }
+ }
+
+ class2_set.add (0);
+ for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
+ {
+ unsigned klass2 = (this+classDef2).get (cp);
+ class2_set.add (klass2);
+ }
+
+ if (class1_set.is_empty ()
+ || class2_set.is_empty ()
+ || (class2_set.get_population() == 1 && class2_set.has(0)))
+ return;
+
+ unsigned len1 = valueFormat1.get_len ();
+ unsigned len2 = valueFormat2.get_len ();
+ const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
+ for (const unsigned class1_idx : class1_set.iter ())
+ {
+ for (const unsigned class2_idx : class2_set.iter ())
+ {
+ unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ if (valueFormat1.has_device ())
+ valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
+
+ if (valueFormat2.has_device ())
+ valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
+ }
+ }
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ 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 ();
+ unsigned int record_len = len1 + len2;
+
+ 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))
+ {
+ 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 = 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)
+ buffer->idx++;
+
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ hb_map_t klass1_map;
+ out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
+ out->class1Count = klass1_map.get_population ();
+
+ hb_map_t klass2_map;
+ out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
+ out->class2Count = klass2_map.get_population ();
+
+ unsigned len1 = valueFormat1.get_len ();
+ unsigned len2 = valueFormat2.get_len ();
+
+ hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map);
+
+ out->valueFormat1 = newFormats.first;
+ out->valueFormat2 = newFormats.second;
+
+ for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+ {
+ for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ {
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
+ valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
+ }
+ }
+
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto it =
+ + hb_iter (this+coverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ out->coverage.serialize_serialize (c->serializer, it);
+ return_trace (out->class1Count && out->class2Count && bool (it));
+ }
+
+
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
+ const hb_map_t& klass2_map) const
+ {
+ unsigned len1 = valueFormat1.get_len ();
+ unsigned len2 = valueFormat2.get_len ();
+
+ unsigned format1 = 0;
+ unsigned format2 = 0;
+
+ for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+ {
+ for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ {
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
+ format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+ }
+ }
+
+ return hb_pair (format1, format2);
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh
new file mode 100644
index 0000000000..c4e57bb543
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUP_HH
+#define OT_LAYOUT_GPOS_POSLOOKUP_HH
+
+#include "PosLookupSubTable.hh"
+#include "../../../hb-ot-layout-common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookup : Lookup
+{
+ using SubTable = PosLookupSubTable;
+
+ const SubTable& get_subtable (unsigned int i) const
+ { return Lookup::get_subtable<SubTable> (i); }
+
+ bool is_reverse () const
+ {
+ return false;
+ }
+
+ 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_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { return dispatch (c); }
+
+ 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 ();
+ }
+
+ hb_closure_lookups_context_t::return_t ret = dispatch (c);
+ return ret;
+ }
+
+ template <typename set_t>
+ void collect_coverage (set_t *glyphs) const
+ {
+ hb_collect_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
+ }
+
+ template <typename context_t>
+ static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int 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); }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_POSLOOKUP_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh
new file mode 100644
index 0000000000..c19fbc323f
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+
+#include "SinglePos.hh"
+#include "PairPos.hh"
+#include "CursivePos.hh"
+#include "MarkBasePos.hh"
+#include "MarkLigPos.hh"
+#include "MarkMarkPos.hh"
+#include "ContextPos.hh"
+#include "ChainContextPos.hh"
+#include "ExtensionPos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookupSubTable
+{
+ friend struct ::OT::Lookup;
+ friend struct PosLookup;
+
+ enum Type {
+ Single = 1,
+ Pair = 2,
+ Cursive = 3,
+ MarkBase = 4,
+ MarkLig = 5,
+ MarkMark = 6,
+ Context = 7,
+ ChainContext = 8,
+ Extension = 9
+ };
+
+ 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 Pair: return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
+ case Cursive: return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
+ case MarkBase: return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
+ case MarkLig: return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
+ case MarkMark: return_trace (u.markMark.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)...));
+ 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 {
+ SinglePos single;
+ PairPos pair;
+ CursivePos cursive;
+ MarkBasePos markBase;
+ MarkLigPos markLig;
+ MarkMarkPos markMark;
+ ContextPos context;
+ ChainContextPos chainContext;
+ ExtensionPos extension;
+ } u;
+ public:
+ DEFINE_SIZE_MIN (0);
+};
+
+}
+}
+}
+
+#endif /* HB_OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
new file mode 100644
index 0000000000..57e146befd
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
@@ -0,0 +1,98 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOS_HH
+#define OT_LAYOUT_GPOS_SINGLEPOS_HH
+
+#include "SinglePosFormat1.hh"
+#include "SinglePosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePos
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ SinglePosFormat1 format1;
+ SinglePosFormat2 format2;
+ } u;
+
+ public:
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned get_format (Iterator glyph_val_iter_pairs)
+ {
+ hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+ for (const auto iter : glyph_val_iter_pairs)
+ for (const auto _ : hb_zip (iter.second, first_val_iter))
+ if (_.first != _.second)
+ return 2;
+
+ return 1;
+ }
+
+ template<typename Iterator,
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ const SrcLookup* src,
+ Iterator glyph_val_iter_pairs,
+ const hb_map_t *layout_variation_idx_map)
+ {
+ if (unlikely (!c->extend_min (u.format))) return;
+ unsigned format = 2;
+ ValueFormat new_format = src->get_value_format ();
+
+ if (glyph_val_iter_pairs)
+ {
+ format = get_format (glyph_val_iter_pairs);
+ new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
+ }
+
+ u.format = format;
+ switch (u.format) {
+ case 1: u.format1.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_map);
+ return;
+ case 2: u.format2.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_map);
+ return;
+ default:return;
+ }
+ }
+
+ 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, typename SrcLookup>
+static void
+SinglePos_serialize (hb_serialize_context_t *c,
+ const SrcLookup *src,
+ Iterator it,
+ const hb_map_t *layout_variation_idx_map)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
new file mode 100644
index 0000000000..8b7840ed0e
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -0,0 +1,124 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+
+#include "Common.hh"
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat; /* Defines the types of data in the
+ * ValueRecord */
+ ValueRecord values; /* Defines positioning
+ * value(s)--applied to all glyphs in
+ * the Coverage table */
+ public:
+ DEFINE_SIZE_ARRAY (6, values);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ valueFormat.sanitize_value (c, this, values));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ if (!valueFormat.has_device ()) return;
+
+ auto it =
+ + hb_iter (this+coverage)
+ | hb_filter (c->glyph_set)
+ ;
+
+ if (!it) return;
+ valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ ValueFormat get_value_format () const { return valueFormat; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ valueFormat.apply_value (c, this, values, buffer->cur_pos());
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ template<typename Iterator,
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ const SrcLookup *src,
+ Iterator it,
+ ValueFormat newFormat,
+ const hb_map_t *layout_variation_idx_map)
+ {
+ if (unlikely (!c->extend_min (this))) return;
+ if (unlikely (!c->check_assign (valueFormat,
+ newFormat,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+
+ for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
+ {
+ src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map);
+ // Only serialize the first entry in the iterator, the rest are assumed to
+ // be the same.
+ break;
+ }
+
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ 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 it =
+ + hb_iter (this+coverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting (glyph_map)
+ | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
+ ;
+
+ bool ret = bool (it);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+ return_trace (ret);
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
new file mode 100644
index 0000000000..0d038b4422
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -0,0 +1,140 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 2 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat; /* Defines the types of data in the
+ * ValueRecord */
+ HBUINT16 valueCount; /* Number of ValueRecords */
+ ValueRecord values; /* Array of ValueRecords--positioning
+ * values applied to glyphs */
+ public:
+ DEFINE_SIZE_ARRAY (8, values);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ valueFormat.sanitize_values (c, this, values, valueCount));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ if (!valueFormat.has_device ()) return;
+
+ auto it =
+ + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+ | hb_filter (c->glyph_set, hb_first)
+ ;
+
+ if (!it) return;
+
+ unsigned sub_length = valueFormat.get_len ();
+ const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
+
+ for (unsigned i : + it
+ | hb_map (hb_second))
+ valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
+
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ ValueFormat get_value_format () const { return valueFormat; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ if (likely (index >= valueCount)) return_trace (false);
+
+ valueFormat.apply_value (c, this,
+ &values[index * valueFormat.get_len ()],
+ buffer->cur_pos());
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ template<typename Iterator,
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ const SrcLookup *src,
+ Iterator it,
+ ValueFormat newFormat,
+ const hb_map_t *layout_variation_idx_map)
+ {
+ auto out = c->extend_min (this);
+ if (unlikely (!out)) return;
+ if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+ if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
+
+ + it
+ | hb_map (hb_second)
+ | hb_apply ([&] (hb_array_t<const Value> _)
+ { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
+ ;
+
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ 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;
+
+ unsigned sub_length = valueFormat.get_len ();
+ auto values_array = values.as_array (valueCount * sub_length);
+
+ auto it =
+ + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+ | hb_filter (glyphset, hb_first)
+ | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+ {
+ return hb_pair (glyph_map[_.first],
+ values_array.sub_array (_.second * sub_length,
+ sub_length));
+ })
+ ;
+
+ bool ret = bool (it);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+ return_trace (ret);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
new file mode 100644
index 0000000000..b29f287bce
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
@@ -0,0 +1,329 @@
+#ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
+#define OT_LAYOUT_GPOS_VALUEFORMAT_HH
+
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef HBUINT16 Value;
+
+typedef UnsizedArrayOf<Value> ValueRecord;
+
+struct ValueFormat : HBUINT16
+{
+ enum Flags {
+ xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
+ yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
+ xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
+ yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
+ xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
+ yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
+ xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
+ yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
+ ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
+ reserved = 0xF000u, /* For future use */
+
+ devices = 0x00F0u /* Mask for having any Device table */
+ };
+
+/* All fields are options. Only those available advance the value pointer. */
+#if 0
+ HBINT16 xPlacement; /* Horizontal adjustment for
+ * placement--in design units */
+ HBINT16 yPlacement; /* Vertical adjustment for
+ * placement--in design units */
+ HBINT16 xAdvance; /* Horizontal adjustment for
+ * advance--in design units (only used
+ * for horizontal writing) */
+ HBINT16 yAdvance; /* Vertical adjustment for advance--in
+ * design units (only used for vertical
+ * writing) */
+ Offset16To<Device> xPlaDevice; /* Offset to Device table for
+ * horizontal placement--measured from
+ * beginning of PosTable (may be NULL) */
+ Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical
+ * placement--measured from beginning
+ * of PosTable (may be NULL) */
+ Offset16To<Device> xAdvDevice; /* Offset to Device table for
+ * horizontal advance--measured from
+ * beginning of PosTable (may be NULL) */
+ Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical
+ * advance--measured from beginning of
+ * PosTable (may be NULL) */
+#endif
+
+ IntType& operator = (uint16_t i) { v = i; return *this; }
+
+ unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
+ unsigned int get_size () const { return get_len () * Value::static_size; }
+
+ bool apply_value (hb_ot_apply_context_t *c,
+ const void *base,
+ const Value *values,
+ hb_glyph_position_t &glyph_pos) const
+ {
+ bool ret = false;
+ unsigned int format = *this;
+ if (!format) return ret;
+
+ hb_font_t *font = c->font;
+ bool horizontal =
+#ifndef HB_NO_VERTICAL
+ HB_DIRECTION_IS_HORIZONTAL (c->direction)
+#else
+ true
+#endif
+ ;
+
+ if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret));
+ if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret));
+ if (format & xAdvance) {
+ if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
+ values++;
+ }
+ /* y_advance values grow downward but font-space grows upward, hence negation */
+ if (format & yAdvance) {
+ if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
+ values++;
+ }
+
+ if (!has_device ()) return ret;
+
+ bool use_x_device = font->x_ppem || font->num_coords;
+ bool use_y_device = font->y_ppem || font->num_coords;
+
+ if (!use_x_device && !use_y_device) return ret;
+
+ const VariationStore &store = c->var_store;
+ auto *cache = c->var_store_cache;
+
+ /* pixel -> fractional pixel */
+ if (format & xPlaDevice) {
+ if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ values++;
+ }
+ if (format & yPlaDevice) {
+ if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ values++;
+ }
+ if (format & xAdvDevice) {
+ if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ values++;
+ }
+ if (format & yAdvDevice) {
+ /* y_advance values grow downward but font-space grows upward, hence negation */
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ values++;
+ }
+ return ret;
+ }
+
+ unsigned int get_effective_format (const Value *values) const
+ {
+ unsigned int format = *this;
+ for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
+ if (format & flag) should_drop (*values++, (Flags) flag, &format);
+ }
+
+ return format;
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned int get_effective_format (Iterator it) const {
+ unsigned int new_format = 0;
+
+ for (const hb_array_t<const Value>& values : it)
+ new_format = new_format | get_effective_format (&values);
+
+ return new_format;
+ }
+
+ void copy_values (hb_serialize_context_t *c,
+ unsigned int new_format,
+ const void *base,
+ const Value *values,
+ const hb_map_t *layout_variation_idx_map) const
+ {
+ unsigned int format = *this;
+ if (!format) return;
+
+ if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
+ if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
+ if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++);
+ if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++);
+
+ if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+ if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+ if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+ if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+ }
+
+ void copy_value (hb_serialize_context_t *c,
+ unsigned int new_format,
+ Flags flag,
+ Value value) const
+ {
+ // Filter by new format.
+ if (!(new_format & flag)) return;
+ c->copy (value);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+ const void *base,
+ const hb_array_t<const Value>& values) const
+ {
+ unsigned format = *this;
+ unsigned i = 0;
+ if (format & xPlacement) i++;
+ if (format & yPlacement) i++;
+ if (format & xAdvance) i++;
+ if (format & yAdvance) i++;
+ if (format & xPlaDevice)
+ {
+ (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ i++;
+ }
+
+ if (format & ValueFormat::yPlaDevice)
+ {
+ (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ i++;
+ }
+
+ if (format & ValueFormat::xAdvDevice)
+ {
+
+ (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ i++;
+ }
+
+ if (format & ValueFormat::yAdvDevice)
+ {
+
+ (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+ i++;
+ }
+ }
+
+ private:
+ bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
+ unsigned int format = *this;
+
+ if (format & xPlacement) values++;
+ if (format & yPlacement) values++;
+ if (format & xAdvance) values++;
+ if (format & yAdvance) values++;
+
+ if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+
+ return true;
+ }
+
+ static inline Offset16To<Device>& get_device (Value* value)
+ {
+ return *static_cast<Offset16To<Device> *> (value);
+ }
+ static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
+ {
+ if (worked) *worked |= bool (*value);
+ return *static_cast<const Offset16To<Device> *> (value);
+ }
+
+ bool copy_device (hb_serialize_context_t *c, const void *base,
+ const Value *src_value, const hb_map_t *layout_variation_idx_map) const
+ {
+ Value *dst_value = c->copy (*src_value);
+
+ if (!dst_value) return false;
+ if (*dst_value == 0) return true;
+
+ *dst_value = 0;
+ c->push ();
+ if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
+ {
+ c->add_link (*dst_value, c->pop_pack ());
+ return true;
+ }
+ else
+ {
+ c->pop_discard ();
+ return false;
+ }
+ }
+
+ static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+ {
+ if (worked) *worked |= bool (*value);
+ return *reinterpret_cast<const HBINT16 *> (value);
+ }
+
+ public:
+
+ bool has_device () const
+ {
+ unsigned int format = *this;
+ return (format & devices) != 0;
+ }
+
+ bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+ }
+
+ bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int len = get_len ();
+
+ if (!c->check_range (values, count, get_size ())) return_trace (false);
+
+ if (!has_device ()) return_trace (true);
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+ return_trace (false);
+ values += len;
+ }
+
+ return_trace (true);
+ }
+
+ /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
+ bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+ {
+ TRACE_SANITIZE (this);
+
+ if (!has_device ()) return_trace (true);
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+ return_trace (false);
+ values += stride;
+ }
+
+ return_trace (true);
+ }
+
+ private:
+
+ void should_drop (Value value, Flags flag, unsigned int* format) const
+ {
+ if (value) return;
+ *format = *format & ~flag;
+ }
+
+};
+
+}
+}
+}
+
+#endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
index ad153ce8d7..3f0c4b2ad9 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
@@ -19,6 +19,8 @@ namespace GSUB {
struct GSUB : GSUBGPOS
{
+ using Lookup = SubstLookup;
+
static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
const SubstLookup& get_lookup (unsigned int i) const
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
index 3419b5a734..8fb3b55097 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
@@ -10,7 +10,7 @@ namespace GSUB {
struct SubstLookup : Lookup
{
- typedef SubstLookupSubTable SubTable;
+ using SubTable = SubstLookupSubTable;
bool sanitize (hb_sanitize_context_t *c) const
{ return Lookup::sanitize<SubTable> (c); }
@@ -73,8 +73,6 @@ struct SubstLookup : Lookup
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;
}
@@ -100,8 +98,6 @@ struct SubstLookup : Lookup
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,
@@ -206,8 +202,6 @@ struct SubstLookup : Lookup
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)...); }
diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
new file mode 100644
index 0000000000..c145beaa49
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
@@ -0,0 +1,258 @@
+#ifndef OT_GLYF_COMPOSITEGLYPH_HH
+#define OT_GLYF_COMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct CompositeGlyphRecord
+{
+ protected:
+ enum composite_glyph_flag_t
+ {
+ ARG_1_AND_2_ARE_WORDS = 0x0001,
+ ARGS_ARE_XY_VALUES = 0x0002,
+ ROUND_XY_TO_GRID = 0x0004,
+ WE_HAVE_A_SCALE = 0x0008,
+ MORE_COMPONENTS = 0x0020,
+ WE_HAVE_AN_X_AND_Y_SCALE = 0x0040,
+ WE_HAVE_A_TWO_BY_TWO = 0x0080,
+ WE_HAVE_INSTRUCTIONS = 0x0100,
+ USE_MY_METRICS = 0x0200,
+ OVERLAP_COMPOUND = 0x0400,
+ SCALED_COMPONENT_OFFSET = 0x0800,
+ UNSCALED_COMPONENT_OFFSET = 0x1000
+ };
+
+ public:
+ unsigned int get_size () const
+ {
+ unsigned int size = min_size;
+ /* arg1 and 2 are int16 */
+ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
+ /* arg1 and 2 are int8 */
+ else size += 2;
+
+ /* One x 16 bit (scale) */
+ if (flags & WE_HAVE_A_SCALE) size += 2;
+ /* Two x 16 bit (xscale, yscale) */
+ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
+ /* Four x 16 bit (xscale, scale01, scale10, yscale) */
+ else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
+
+ return size;
+ }
+
+ void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
+ void set_overlaps_flag ()
+ {
+ flags = (uint16_t) flags | OVERLAP_COMPOUND;
+ }
+
+ bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; }
+
+ bool has_more () const { return flags & MORE_COMPONENTS; }
+ bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
+ bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); }
+ void get_anchor_points (unsigned int &point1, unsigned int &point2) const
+ {
+ const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
+ if (flags & ARG_1_AND_2_ARE_WORDS)
+ {
+ point1 = ((const HBUINT16 *) p)[0];
+ point2 = ((const HBUINT16 *) p)[1];
+ }
+ else
+ {
+ point1 = p[0];
+ point2 = p[1];
+ }
+ }
+
+ void transform_points (contour_point_vector_t &points) const
+ {
+ float matrix[4];
+ contour_point_t trans;
+ if (get_transformation (matrix, trans))
+ {
+ if (scaled_offsets ())
+ {
+ points.translate (trans);
+ points.transform (matrix);
+ }
+ else
+ {
+ points.transform (matrix);
+ points.translate (trans);
+ }
+ }
+ }
+
+ protected:
+ bool scaled_offsets () const
+ { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
+
+ bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
+ {
+ matrix[0] = matrix[3] = 1.f;
+ matrix[1] = matrix[2] = 0.f;
+
+ int tx, ty;
+ const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
+ if (flags & ARG_1_AND_2_ARE_WORDS)
+ {
+ tx = *(const HBINT16 *) p;
+ p += HBINT16::static_size;
+ ty = *(const HBINT16 *) p;
+ p += HBINT16::static_size;
+ }
+ else
+ {
+ tx = *p++;
+ ty = *p++;
+ }
+ if (is_anchored ()) tx = ty = 0;
+
+ trans.init ((float) tx, (float) ty);
+
+ {
+ const F2DOT14 *points = (const F2DOT14 *) p;
+ if (flags & WE_HAVE_A_SCALE)
+ {
+ matrix[0] = matrix[3] = points[0].to_float ();
+ return true;
+ }
+ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
+ {
+ matrix[0] = points[0].to_float ();
+ matrix[3] = points[1].to_float ();
+ return true;
+ }
+ else if (flags & WE_HAVE_A_TWO_BY_TWO)
+ {
+ matrix[0] = points[0].to_float ();
+ matrix[1] = points[1].to_float ();
+ matrix[2] = points[2].to_float ();
+ matrix[3] = points[3].to_float ();
+ return true;
+ }
+ }
+ return tx || ty;
+ }
+
+ public:
+ HBUINT16 flags;
+ HBGlyphID16 glyphIndex;
+ public:
+ DEFINE_SIZE_MIN (4);
+};
+
+struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphRecord &>
+{
+ typedef const CompositeGlyphRecord *__item_t__;
+ composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
+ glyph (glyph_), current (nullptr), current_size (0)
+ {
+ set_current (current_);
+ }
+
+ composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
+
+ item_t __item__ () const { return *current; }
+ bool __more__ () const { return current; }
+ void __next__ ()
+ {
+ if (!current->has_more ()) { current = nullptr; return; }
+
+ set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
+ }
+ composite_iter_t __end__ () const { return composite_iter_t (); }
+ bool operator != (const composite_iter_t& o) const
+ { return current != o.current; }
+
+
+ void set_current (__item_t__ current_)
+ {
+ if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
+ {
+ current = nullptr;
+ current_size = 0;
+ return;
+ }
+ unsigned size = current_->get_size ();
+ if (!glyph.check_range (current_, size))
+ {
+ current = nullptr;
+ current_size = 0;
+ return;
+ }
+
+ current = current_;
+ current_size = size;
+ }
+
+ private:
+ hb_bytes_t glyph;
+ __item_t__ current;
+ unsigned current_size;
+};
+
+struct CompositeGlyph
+{
+ const GlyphHeader &header;
+ hb_bytes_t bytes;
+ CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+ header (header_), bytes (bytes_) {}
+
+ composite_iter_t iter () const
+ { return composite_iter_t (bytes, &StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); }
+
+ unsigned int instructions_length (hb_bytes_t bytes) const
+ {
+ unsigned int start = bytes.length;
+ unsigned int end = bytes.length;
+ const CompositeGlyphRecord *last = nullptr;
+ for (auto &item : iter ())
+ last = &item;
+ if (unlikely (!last)) return 0;
+
+ if (last->has_instructions ())
+ start = (char *) last - &bytes + last->get_size ();
+ if (unlikely (start > end)) return 0;
+ return end - start;
+ }
+
+ /* Trimming for composites not implemented.
+ * If removing hints it falls out of that. */
+ const hb_bytes_t trim_padding () const { return bytes; }
+
+ void drop_hints ()
+ {
+ for (const auto &_ : iter ())
+ const_cast<CompositeGlyphRecord &> (_).drop_instructions_flag ();
+ }
+
+ /* Chop instructions off the end */
+ void drop_hints_bytes (hb_bytes_t &dest_start) const
+ { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
+
+ void set_overlaps_flag ()
+ {
+ CompositeGlyphRecord& glyph_chain = const_cast<CompositeGlyphRecord &> (
+ StructAfter<CompositeGlyphRecord, GlyphHeader> (header));
+ if (!bytes.check_range(&glyph_chain, CompositeGlyphRecord::min_size))
+ return;
+ glyph_chain.set_overlaps_flag ();
+ }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_COMPOSITEGLYPH_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
new file mode 100644
index 0000000000..2199d2c48b
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
@@ -0,0 +1,233 @@
+#ifndef OT_GLYF_GLYPH_HH
+#define OT_GLYF_GLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+#include "GlyphHeader.hh"
+#include "SimpleGlyph.hh"
+#include "CompositeGlyph.hh"
+
+
+namespace OT {
+
+struct glyf_accelerator_t;
+
+namespace glyf_impl {
+
+
+enum phantom_point_index_t
+{
+ PHANTOM_LEFT = 0,
+ PHANTOM_RIGHT = 1,
+ PHANTOM_TOP = 2,
+ PHANTOM_BOTTOM = 3,
+ PHANTOM_COUNT = 4
+};
+
+struct Glyph
+{
+ enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
+
+ public:
+ composite_iter_t get_composite_iterator () const
+ {
+ if (type != COMPOSITE) return composite_iter_t ();
+ return CompositeGlyph (*header, bytes).iter ();
+ }
+
+ const hb_bytes_t trim_padding () const
+ {
+ switch (type) {
+ case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
+ case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
+ default: return bytes;
+ }
+ }
+
+ void drop_hints ()
+ {
+ switch (type) {
+ case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
+ case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
+ default: return;
+ }
+ }
+
+ void set_overlaps_flag ()
+ {
+ switch (type) {
+ case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
+ case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
+ default: return;
+ }
+ }
+
+ void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+ {
+ switch (type) {
+ case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
+ case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
+ default: return;
+ }
+ }
+
+ /* Note: Recursively calls itself.
+ * all_points includes phantom points
+ */
+ template <typename accelerator_t>
+ bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
+ contour_point_vector_t &all_points /* OUT */,
+ bool phantom_only = false,
+ unsigned int depth = 0) const
+ {
+ if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+ contour_point_vector_t stack_points;
+ bool inplace = type == SIMPLE && all_points.length == 0;
+ /* Load into all_points if it's empty, as an optimization. */
+ contour_point_vector_t &points = inplace ? all_points : stack_points;
+
+ switch (type) {
+ case COMPOSITE:
+ {
+ /* pseudo component points for each component in composite glyph */
+ unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
+ if (unlikely (!points.resize (num_points))) return false;
+ break;
+ }
+ case SIMPLE:
+ if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+ return false;
+ break;
+ }
+
+ /* Init phantom points */
+ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+ hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+ {
+ int h_delta = (int) header->xMin -
+ glyf_accelerator.hmtx->get_side_bearing (gid);
+ int v_orig = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+ glyf_accelerator.vmtx->get_side_bearing (gid)
+#else
+ 0
+#endif
+ ;
+ unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
+ unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+ glyf_accelerator.vmtx->get_advance (gid)
+#else
+ - font->face->get_upem ()
+#endif
+ ;
+ phantoms[PHANTOM_LEFT].x = h_delta;
+ phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
+ phantoms[PHANTOM_TOP].y = v_orig;
+ phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+ }
+
+#ifndef HB_NO_VAR
+ glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
+#endif
+
+ switch (type) {
+ case SIMPLE:
+ if (!inplace)
+ all_points.extend (points.as_array ());
+ break;
+ case COMPOSITE:
+ {
+ contour_point_vector_t comp_points;
+ unsigned int comp_index = 0;
+ for (auto &item : get_composite_iterator ())
+ {
+ comp_points.reset ();
+ if (unlikely (!glyf_accelerator.glyph_for_gid (item.glyphIndex)
+ .get_points (font, glyf_accelerator, comp_points,
+ phantom_only, depth + 1)))
+ return false;
+
+ /* Copy phantom points from component if USE_MY_METRICS flag set */
+ if (item.is_use_my_metrics ())
+ for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+ phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+ /* Apply component transformation & translation */
+ item.transform_points (comp_points);
+
+ /* Apply translation from gvar */
+ comp_points.translate (points[comp_index]);
+
+ if (item.is_anchored ())
+ {
+ unsigned int p1, p2;
+ item.get_anchor_points (p1, p2);
+ if (likely (p1 < all_points.length && p2 < comp_points.length))
+ {
+ contour_point_t delta;
+ delta.init (all_points[p1].x - comp_points[p2].x,
+ all_points[p1].y - comp_points[p2].y);
+
+ comp_points.translate (delta);
+ }
+ }
+
+ all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+ comp_index++;
+ }
+
+ all_points.extend (phantoms);
+ } break;
+ default:
+ all_points.extend (phantoms);
+ }
+
+ if (depth == 0) /* Apply at top level */
+ {
+ /* Undocumented rasterizer behavior:
+ * Shift points horizontally by the updated left side bearing
+ */
+ contour_point_t delta;
+ delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
+ if (delta.x) all_points.translate (delta);
+ }
+
+ return !all_points.in_error ();
+ }
+
+ bool get_extents (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
+ hb_glyph_extents_t *extents) const
+ {
+ if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+ return header->get_extents (font, glyf_accelerator, gid, extents);
+ }
+
+ hb_bytes_t get_bytes () const { return bytes; }
+
+ Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
+ hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_),
+ header (bytes.as<GlyphHeader> ()),
+ gid (gid_)
+ {
+ int num_contours = header->numberOfContours;
+ if (unlikely (num_contours == 0)) type = EMPTY;
+ else if (num_contours > 0) type = SIMPLE;
+ else type = COMPOSITE; /* negative numbers */
+ }
+
+ protected:
+ hb_bytes_t bytes;
+ const GlyphHeader *header;
+ hb_codepoint_t gid;
+ unsigned type;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYPH_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh b/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh
new file mode 100644
index 0000000000..792bd5478f
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh
@@ -0,0 +1,48 @@
+#ifndef OT_GLYF_GLYPHHEADER_HH
+#define OT_GLYF_GLYPHHEADER_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct GlyphHeader
+{
+ bool has_data () const { return numberOfContours; }
+
+ template <typename accelerator_t>
+ bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
+ hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+ {
+ /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
+ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
+ extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
+ extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
+ extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
+ extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
+
+ return true;
+ }
+
+ HBINT16 numberOfContours;
+ /* If the number of contours is
+ * greater than or equal to zero,
+ * this is a simple glyph; if negative,
+ * this is a composite glyph. */
+ FWORD xMin; /* Minimum x for coordinate data. */
+ FWORD yMin; /* Minimum y for coordinate data. */
+ FWORD xMax; /* Maximum x for coordinate data. */
+ FWORD yMax; /* Maximum y for coordinate data. */
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYPHHEADER_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
new file mode 100644
index 0000000000..6df978cf13
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
@@ -0,0 +1,216 @@
+#ifndef OT_GLYF_SIMPLEGLYPH_HH
+#define OT_GLYF_SIMPLEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct SimpleGlyph
+{
+ enum simple_glyph_flag_t
+ {
+ FLAG_ON_CURVE = 0x01,
+ FLAG_X_SHORT = 0x02,
+ FLAG_Y_SHORT = 0x04,
+ FLAG_REPEAT = 0x08,
+ FLAG_X_SAME = 0x10,
+ FLAG_Y_SAME = 0x20,
+ FLAG_OVERLAP_SIMPLE = 0x40,
+ FLAG_RESERVED2 = 0x80
+ };
+
+ const GlyphHeader &header;
+ hb_bytes_t bytes;
+ SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+ header (header_), bytes (bytes_) {}
+
+ unsigned int instruction_len_offset () const
+ { return GlyphHeader::static_size + 2 * header.numberOfContours; }
+
+ unsigned int length (unsigned int instruction_len) const
+ { return instruction_len_offset () + 2 + instruction_len; }
+
+ unsigned int instructions_length () const
+ {
+ unsigned int instruction_length_offset = instruction_len_offset ();
+ if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
+
+ const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
+ /* Out of bounds of the current glyph */
+ if (unlikely (length (instructionLength) > bytes.length)) return 0;
+ return instructionLength;
+ }
+
+ const hb_bytes_t trim_padding () const
+ {
+ /* based on FontTools _g_l_y_f.py::trim */
+ const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
+ const uint8_t *glyph_end = glyph + bytes.length;
+ /* simple glyph w/contours, possibly trimmable */
+ glyph += instruction_len_offset ();
+
+ if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
+ unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
+ unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
+
+ glyph += 2 + num_instructions;
+
+ unsigned int coord_bytes = 0;
+ unsigned int coords_with_flags = 0;
+ while (glyph < glyph_end)
+ {
+ uint8_t flag = *glyph;
+ glyph++;
+
+ unsigned int repeat = 1;
+ if (flag & FLAG_REPEAT)
+ {
+ if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
+ repeat = *glyph + 1;
+ glyph++;
+ }
+
+ unsigned int xBytes, yBytes;
+ xBytes = yBytes = 0;
+ if (flag & FLAG_X_SHORT) xBytes = 1;
+ else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
+
+ if (flag & FLAG_Y_SHORT) yBytes = 1;
+ else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
+
+ coord_bytes += (xBytes + yBytes) * repeat;
+ coords_with_flags += repeat;
+ if (coords_with_flags >= num_coordinates) break;
+ }
+
+ if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t ();
+ return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph));
+ }
+
+ /* zero instruction length */
+ void drop_hints ()
+ {
+ GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
+ (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
+ }
+
+ void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+ {
+ unsigned int instructions_len = instructions_length ();
+ unsigned int glyph_length = length (instructions_len);
+ dest_start = bytes.sub_array (0, glyph_length - instructions_len);
+ dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
+ }
+
+ void set_overlaps_flag ()
+ {
+ if (unlikely (!header.numberOfContours)) return;
+
+ unsigned flags_offset = length (instructions_length ());
+ 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;
+ }
+
+ static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
+ contour_point_vector_t &points_ /* IN/OUT */,
+ const HBUINT8 *end)
+ {
+ unsigned count = points_.length;
+ for (unsigned int i = 0; i < count;)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ uint8_t flag = *p++;
+ points_.arrayZ[i++].flag = flag;
+ if (flag & FLAG_REPEAT)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ unsigned int repeat_count = *p++;
+ unsigned stop = hb_min (i + repeat_count, count);
+ for (; i < stop;)
+ points_.arrayZ[i++].flag = flag;
+ }
+ }
+ return true;
+ }
+
+ static bool read_points (const HBUINT8 *&p /* IN/OUT */,
+ contour_point_vector_t &points_ /* IN/OUT */,
+ const HBUINT8 *end,
+ float contour_point_t::*m,
+ const simple_glyph_flag_t short_flag,
+ const simple_glyph_flag_t same_flag)
+ {
+ int v = 0;
+
+ unsigned count = points_.length;
+ for (unsigned i = 0; i < count; i++)
+ {
+ unsigned flag = points_[i].flag;
+ if (flag & short_flag)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ if (flag & same_flag)
+ v += *p++;
+ else
+ v -= *p++;
+ }
+ else
+ {
+ if (!(flag & same_flag))
+ {
+ if (unlikely (p + HBINT16::static_size > end)) return false;
+ v += *(const HBINT16 *) p;
+ p += HBINT16::static_size;
+ }
+ }
+ points_.arrayZ[i].*m = v;
+ }
+ return true;
+ }
+
+ bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+ bool phantom_only = false) const
+ {
+ const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
+ int num_contours = header.numberOfContours;
+ assert (num_contours);
+ /* One extra item at the end, for the instruction-count below. */
+ if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
+ unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
+
+ points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy
+ if (!points_.resize (num_points)) return false;
+ if (phantom_only) return true;
+
+ for (int i = 0; i < num_contours; i++)
+ points_[endPtsOfContours[i]].is_end_point = true;
+
+ /* Skip instructions */
+ const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
+ endPtsOfContours[num_contours]);
+
+ if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */
+ const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length);
+ if (unlikely (p >= end)) return false;
+
+ /* Read x & y coordinates */
+ return read_flags (p, points_, end)
+ && read_points (p, points_, end, &contour_point_t::x,
+ FLAG_X_SHORT, FLAG_X_SAME)
+ && read_points (p, points_, end, &contour_point_t::y,
+ FLAG_Y_SHORT, FLAG_Y_SAME);
+ }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_SIMPLEGLYPH_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
new file mode 100644
index 0000000000..ebe4372047
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
@@ -0,0 +1,72 @@
+#ifndef OT_GLYF_SUBSETGLYPH_HH
+#define OT_GLYF_SUBSETGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct SubsetGlyph
+{
+ hb_codepoint_t new_gid;
+ hb_codepoint_t old_gid;
+ Glyph source_glyph;
+ hb_bytes_t dest_start; /* region of source_glyph to copy first */
+ hb_bytes_t dest_end; /* region of source_glyph to copy second */
+
+ bool serialize (hb_serialize_context_t *c,
+ bool use_short_loca,
+ const hb_subset_plan_t *plan) const
+ {
+ TRACE_SERIALIZE (this);
+
+ hb_bytes_t dest_glyph = dest_start.copy (c);
+ dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
+ unsigned int pad_length = use_short_loca ? padding () : 0;
+ DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
+
+ HBUINT8 pad;
+ pad = 0;
+ while (pad_length > 0)
+ {
+ c->embed (pad);
+ pad_length--;
+ }
+
+ if (unlikely (!dest_glyph.length)) return_trace (true);
+
+ /* update components gids */
+ for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
+ {
+ hb_codepoint_t new_gid;
+ if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid))
+ const_cast<CompositeGlyphRecord &> (_).glyphIndex = new_gid;
+ }
+
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ Glyph (dest_glyph).drop_hints ();
+
+ if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
+ Glyph (dest_glyph).set_overlaps_flag ();
+
+ return_trace (true);
+ }
+
+ void drop_hints_bytes ()
+ { source_glyph.drop_hints_bytes (dest_start, dest_end); }
+
+ unsigned int length () const { return dest_start.length + dest_end.length; }
+ /* pad to 2 to ensure 2-byte loca will be ok */
+ unsigned int padding () const { return length () % 2; }
+ unsigned int padded_size () const { return length () + padding (); }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_SUBSETGLYPH_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
new file mode 100644
index 0000000000..f51f7a81fc
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
@@ -0,0 +1,90 @@
+#ifndef OT_GLYF_GLYF_HELPERS_HH
+#define OT_GLYF_GLYF_HELPERS_HH
+
+
+#include "../../hb-open-type.hh"
+#include "../../hb-subset-plan.hh"
+
+#include "loca.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+template<typename IteratorIn, typename IteratorOut,
+ hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
+ hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+static void
+_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest)
+{
+ unsigned right_shift = short_offsets ? 1 : 0;
+ unsigned int offset = 0;
+ dest << 0;
+ + it
+ | hb_map ([=, &offset] (unsigned int padded_size)
+ {
+ offset += padded_size;
+ DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
+ return offset >> right_shift;
+ })
+ | hb_sink (dest)
+ ;
+}
+
+static bool
+_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
+{
+ hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source);
+ hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
+ hb_blob_destroy (head_blob);
+
+ if (unlikely (!head_prime_blob))
+ return false;
+
+ head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
+ head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
+ bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
+
+ hb_blob_destroy (head_prime_blob);
+ return success;
+}
+
+template<typename Iterator,
+ hb_requires (hb_is_source_of (Iterator, unsigned int))>
+static bool
+_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
+{
+ unsigned num_offsets = padded_offsets.len () + 1;
+ unsigned entry_size = use_short_loca ? 2 : 4;
+ char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
+
+ if (unlikely (!loca_prime_data)) return false;
+
+ DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
+ entry_size, num_offsets, entry_size * num_offsets);
+
+ if (use_short_loca)
+ _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
+ else
+ _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
+
+ hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
+ entry_size * num_offsets,
+ HB_MEMORY_MODE_WRITABLE,
+ loca_prime_data,
+ hb_free);
+
+ bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
+ && _add_head_and_set_loca_version (plan, use_short_loca);
+
+ hb_blob_destroy (loca_blob);
+ return result;
+}
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYF_HELPERS_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
new file mode 100644
index 0000000000..f74513cb96
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
@@ -0,0 +1,388 @@
+#ifndef OT_GLYF_GLYF_HH
+#define OT_GLYF_GLYF_HH
+
+
+#include "../../hb-open-type.hh"
+#include "../../hb-ot-head-table.hh"
+#include "../../hb-ot-hmtx-table.hh"
+#include "../../hb-ot-var-gvar-table.hh"
+#include "../../hb-draw.hh"
+
+#include "glyf-helpers.hh"
+#include "Glyph.hh"
+#include "SubsetGlyph.hh"
+#include "loca.hh"
+#include "path-builder.hh"
+
+
+namespace OT {
+
+
+/*
+ * glyf -- TrueType Glyph Data
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
+ */
+#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
+
+
+struct glyf
+{
+ friend struct glyf_accelerator_t;
+
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
+
+ bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
+ {
+ TRACE_SANITIZE (this);
+ /* Runtime checks as eager sanitizing each glyph is costy */
+ return_trace (true);
+ }
+
+ /* requires source of SubsetGlyph complains the identifier isn't declared */
+ template <typename Iterator>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator it,
+ bool use_short_loca,
+ const hb_subset_plan_t *plan)
+ {
+ TRACE_SERIALIZE (this);
+ unsigned init_len = c->length ();
+ for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
+
+ /* As a special case when all glyph in the font are empty, add a zero byte
+ * to the table, so that OTS doesn’t reject it, and to make the table work
+ * on Windows as well.
+ * See https://github.com/khaledhosny/ots/issues/52 */
+ if (init_len == c->length ())
+ {
+ HBUINT8 empty_byte;
+ empty_byte = 0;
+ c->copy (empty_byte);
+ }
+ return_trace (true);
+ }
+
+ /* Byte region(s) per glyph to output
+ unpadded, hints removed if so requested
+ If we fail to process a glyph we produce an empty (0-length) glyph */
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+
+ glyf *glyf_prime = c->serializer->start_embed <glyf> ();
+ if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
+
+ hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
+ _populate_subset_glyphs (c->plan, &glyphs);
+
+ auto padded_offsets =
+ + hb_iter (glyphs)
+ | hb_map (&glyf_impl::SubsetGlyph::padded_size)
+ ;
+
+ unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
+ bool use_short_loca = max_offset < 0x1FFFF;
+
+
+ glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
+ if (!use_short_loca) {
+ padded_offsets =
+ + hb_iter (glyphs)
+ | hb_map (&glyf_impl::SubsetGlyph::length)
+ ;
+ }
+
+
+ if (unlikely (c->serializer->in_error ())) return_trace (false);
+ return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
+ padded_offsets,
+ use_short_loca)));
+ }
+
+ void
+ _populate_subset_glyphs (const hb_subset_plan_t *plan,
+ hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
+
+ protected:
+ UnsizedArrayOf<HBUINT8>
+ dataZ; /* Glyphs data. */
+ public:
+ DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
+ * check the size externally, allow Null() object of it by
+ * defining it _MIN instead. */
+};
+
+struct glyf_accelerator_t
+{
+ glyf_accelerator_t (hb_face_t *face)
+ {
+ short_offset = false;
+ num_glyphs = 0;
+ loca_table = nullptr;
+ glyf_table = nullptr;
+#ifndef HB_NO_VAR
+ gvar = nullptr;
+#endif
+ hmtx = nullptr;
+#ifndef HB_NO_VERTICAL
+ vmtx = nullptr;
+#endif
+ 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 = 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;
+#endif
+ hmtx = face->table.hmtx;
+#ifndef HB_NO_VERTICAL
+ vmtx = face->table.vmtx;
+#endif
+
+ num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+ num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
+ }
+ ~glyf_accelerator_t ()
+ {
+ 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
+ {
+ if (gid >= num_glyphs) return false;
+
+ /* Making this allocfree is not that easy
+ https://github.com/harfbuzz/harfbuzz/issues/2095
+ mostly because of gvar handling in VF fonts,
+ perhaps a separate path for non-VF fonts can be considered */
+ contour_point_vector_t all_points;
+
+ bool phantom_only = !consumer.is_consuming_contour_points ();
+ if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
+ return false;
+
+ if (consumer.is_consuming_contour_points ())
+ {
+ unsigned count = all_points.length;
+ assert (count >= glyf_impl::PHANTOM_COUNT);
+ count -= glyf_impl::PHANTOM_COUNT;
+ for (unsigned point_index = 0; point_index < count; point_index++)
+ consumer.consume_point (all_points[point_index]);
+ consumer.points_end ();
+ }
+
+ /* Where to write phantoms, nullptr if not requested */
+ contour_point_t *phantoms = consumer.get_phantoms_sink ();
+ if (phantoms)
+ for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
+ phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i];
+
+ return true;
+ }
+
+#ifndef HB_NO_VAR
+ struct points_aggregator_t
+ {
+ hb_font_t *font;
+ hb_glyph_extents_t *extents;
+ contour_point_t *phantoms;
+
+ struct contour_bounds_t
+ {
+ contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
+
+ void add (const contour_point_t &p)
+ {
+ min_x = hb_min (min_x, p.x);
+ min_y = hb_min (min_y, p.y);
+ max_x = hb_max (max_x, p.x);
+ max_y = hb_max (max_y, p.y);
+ }
+
+ bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
+
+ void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
+ {
+ if (unlikely (empty ()))
+ {
+ extents->width = 0;
+ extents->x_bearing = 0;
+ extents->height = 0;
+ extents->y_bearing = 0;
+ return;
+ }
+ extents->x_bearing = font->em_scalef_x (min_x);
+ extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
+ extents->y_bearing = font->em_scalef_y (max_y);
+ extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
+ }
+
+ protected:
+ float min_x, min_y, max_x, max_y;
+ } bounds;
+
+ points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
+ {
+ font = font_;
+ extents = extents_;
+ phantoms = phantoms_;
+ if (extents) bounds = contour_bounds_t ();
+ }
+
+ void consume_point (const contour_point_t &point) { bounds.add (point); }
+ void points_end () { bounds.get_extents (font, extents); }
+
+ bool is_consuming_contour_points () { return extents; }
+ contour_point_t *get_phantoms_sink () { return phantoms; }
+ };
+
+ public:
+ unsigned
+ get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+ {
+ if (unlikely (gid >= num_glyphs)) return 0;
+
+ bool success = false;
+
+ contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
+ if (likely (font->num_coords == gvar->get_axis_count ()))
+ success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
+
+ if (unlikely (!success))
+ return
+#ifndef HB_NO_VERTICAL
+ is_vertical ? vmtx->get_advance (gid) :
+#endif
+ hmtx->get_advance (gid);
+
+ float result = is_vertical
+ ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
+ : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x;
+ return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
+ }
+
+ int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+ {
+ if (unlikely (gid >= num_glyphs)) return 0;
+
+ hb_glyph_extents_t extents;
+
+ contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
+ if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
+ return
+#ifndef HB_NO_VERTICAL
+ is_vertical ? vmtx->get_side_bearing (gid) :
+#endif
+ hmtx->get_side_bearing (gid);
+
+ return is_vertical
+ ? ceilf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
+ : floorf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+ }
+#endif
+
+ public:
+ bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+ {
+ if (unlikely (gid >= num_glyphs)) return false;
+
+#ifndef HB_NO_VAR
+ if (font->num_coords)
+ return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
+#endif
+ return glyph_for_gid (gid).get_extents (font, *this, extents);
+ }
+
+ const glyf_impl::Glyph
+ glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
+ {
+ if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph ();
+
+ unsigned int start_offset, end_offset;
+
+ if (short_offset)
+ {
+ const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
+ start_offset = 2 * offsets[gid];
+ end_offset = 2 * offsets[gid + 1];
+ }
+ else
+ {
+ const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
+ start_offset = offsets[gid];
+ end_offset = offsets[gid + 1];
+ }
+
+ if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
+ return glyf_impl::Glyph ();
+
+ glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
+ end_offset - start_offset), gid);
+ return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph;
+ }
+
+ bool
+ get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
+ { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
+
+#ifndef HB_NO_VAR
+ const gvar_accelerator_t *gvar;
+#endif
+ const hmtx_accelerator_t *hmtx;
+#ifndef HB_NO_VERTICAL
+ const vmtx_accelerator_t *vmtx;
+#endif
+
+ private:
+ bool short_offset;
+ unsigned int num_glyphs;
+ hb_blob_ptr_t<loca> loca_table;
+ hb_blob_ptr_t<glyf> glyf_table;
+};
+
+
+inline void
+glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
+ hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
+{
+ OT::glyf_accelerator_t glyf (plan->source);
+
+ + hb_range (plan->num_output_glyphs ())
+ | hb_map ([&] (hb_codepoint_t new_gid)
+ {
+ glyf_impl::SubsetGlyph subset_glyph = {0};
+ subset_glyph.new_gid = new_gid;
+
+ /* should never fail: all old gids should be mapped */
+ if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
+ return subset_glyph;
+
+ if (new_gid == 0 &&
+ !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ subset_glyph.source_glyph = glyf_impl::Glyph ();
+ else
+ subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ subset_glyph.drop_hints_bytes ();
+ else
+ subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+ return subset_glyph;
+ })
+ | hb_sink (glyphs)
+ ;
+}
+
+
+
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYF_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/loca.hh b/thirdparty/harfbuzz/src/OT/glyf/loca.hh
new file mode 100644
index 0000000000..4481cba8ed
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/loca.hh
@@ -0,0 +1,43 @@
+#ifndef OT_GLYF_LOCA_HH
+#define OT_GLYF_LOCA_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+
+
+/*
+ * loca -- Index to Location
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
+ */
+#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
+
+struct loca
+{
+ friend struct glyf;
+ friend struct glyf_accelerator_t;
+
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
+
+ bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (true);
+ }
+
+ protected:
+ UnsizedArrayOf<HBUINT8>
+ dataZ; /* Location data. */
+ public:
+ DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
+ * check the size externally, allow Null() object of it by
+ * defining it _MIN instead. */
+};
+
+
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_LOCA_HH */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
new file mode 100644
index 0000000000..9bfc45a1a6
--- /dev/null
+++ b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
@@ -0,0 +1,135 @@
+#ifndef OT_GLYF_PATH_BUILDER_HH
+#define OT_GLYF_PATH_BUILDER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct path_builder_t
+{
+ hb_font_t *font;
+ hb_draw_session_t *draw_session;
+
+ struct optional_point_t
+ {
+ optional_point_t () {}
+ optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {}
+ operator bool () const { return has_data; }
+
+ bool has_data = false;
+ float x = 0.;
+ float y = 0.;
+
+ optional_point_t lerp (optional_point_t p, float t)
+ { 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_, hb_draw_session_t &draw_session_)
+ {
+ font = font_;
+ draw_session = &draw_session_;
+ first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
+ }
+
+ /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
+ See also:
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
+ * https://stackoverflow.com/a/20772557 */
+ void consume_point (const contour_point_t &point)
+ {
+ bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
+ optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
+ if (!first_oncurve)
+ {
+ if (is_on_curve)
+ {
+ first_oncurve = p;
+ draw_session->move_to (p.x, p.y);
+ }
+ else
+ {
+ if (first_offcurve)
+ {
+ optional_point_t mid = first_offcurve.lerp (p, .5f);
+ first_oncurve = mid;
+ last_offcurve = p;
+ draw_session->move_to (mid.x, mid.y);
+ }
+ else
+ first_offcurve = p;
+ }
+ }
+ else
+ {
+ if (last_offcurve)
+ {
+ if (is_on_curve)
+ {
+ draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+ p.x, p.y);
+ last_offcurve = optional_point_t ();
+ }
+ else
+ {
+ optional_point_t mid = last_offcurve.lerp (p, .5f);
+ draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+ mid.x, mid.y);
+ last_offcurve = p;
+ }
+ }
+ else
+ {
+ if (is_on_curve)
+ draw_session->line_to (p.x, p.y);
+ else
+ last_offcurve = p;
+ }
+ }
+
+ if (point.is_end_point)
+ {
+ if (first_offcurve && last_offcurve)
+ {
+ optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
+ draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+ mid.x, mid.y);
+ last_offcurve = optional_point_t ();
+ /* now check the rest */
+ }
+
+ if (first_offcurve && first_oncurve)
+ draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
+ first_oncurve.x, first_oncurve.y);
+ else if (last_offcurve && first_oncurve)
+ draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+ first_oncurve.x, first_oncurve.y);
+ else if (first_oncurve)
+ draw_session->line_to (first_oncurve.x, first_oncurve.y);
+ else if (first_offcurve)
+ {
+ float x = first_offcurve.x, y = 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_session->close_path ();
+ }
+ }
+ void points_end () {}
+
+ bool is_consuming_contour_points () { return true; }
+ contour_point_t *get_phantoms_sink () { return nullptr; }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_PATH_BUILDER_HH */
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
new file mode 100644
index 0000000000..52ca9dd142
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -0,0 +1,860 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_GRAPH_HH
+#define GRAPH_GRAPH_HH
+
+namespace graph {
+
+/**
+ * Represents a serialized table in the form of a graph.
+ * Provides methods for modifying and reordering the graph.
+ */
+struct graph_t
+{
+ struct vertex_t
+ {
+ hb_serialize_context_t::object_t obj;
+ int64_t distance = 0 ;
+ int64_t space = 0 ;
+ hb_vector_t<unsigned> parents;
+ 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
+ {
+ return parents.length > 1;
+ }
+
+ unsigned incoming_edges () const
+ {
+ return parents.length;
+ }
+
+ void remove_parent (unsigned parent_index)
+ {
+ for (unsigned i = 0; i < parents.length; i++)
+ {
+ if (parents[i] != parent_index) continue;
+ parents.remove (i);
+ break;
+ }
+ }
+
+ void remap_parents (const hb_vector_t<unsigned>& id_map)
+ {
+ for (unsigned i = 0; i < parents.length; i++)
+ parents[i] = id_map[parents[i]];
+ }
+
+ void remap_parent (unsigned old_index, unsigned new_index)
+ {
+ for (unsigned i = 0; i < parents.length; i++)
+ {
+ if (parents[i] == old_index)
+ parents[i] = new_index;
+ }
+ }
+
+ bool is_leaf () const
+ {
+ return !obj.real_links.length && !obj.virtual_links.length;
+ }
+
+ bool raise_priority ()
+ {
+ if (has_max_priority ()) return false;
+ priority++;
+ return true;
+ }
+
+ bool has_max_priority () const {
+ return priority >= 3;
+ }
+
+ int64_t modified_distance (unsigned order) const
+ {
+ // TODO(garretrieger): once priority is high enough, should try
+ // setting distance = 0 which will force to sort immediately after
+ // it's parent where possible.
+
+ int64_t modified_distance =
+ hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
+ if (has_max_priority ()) {
+ modified_distance = 0;
+ }
+ return (modified_distance << 18) | (0x003FFFF & order);
+ }
+
+ int64_t distance_modifier () const
+ {
+ if (!priority) return 0;
+ int64_t table_size = obj.tail - obj.head;
+
+ if (priority == 1)
+ return -table_size / 2;
+
+ return -table_size;
+ }
+ };
+
+ /*
+ * A topological sorting of an object graph. Ordered
+ * in reverse serialization order (first object in the
+ * serialization is at the end of the list). This matches
+ * the 'packed' object stack used internally in the
+ * serializer
+ */
+ template<typename T>
+ graph_t (const T& objects)
+ : parents_invalid (true),
+ distance_invalid (true),
+ positions_invalid (true),
+ successful (true)
+ {
+ 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.
+
+ // If this graph came from a serialization buffer object 0 is the
+ // nil object. We don't need it for our purposes here so drop it.
+ if (i == 0 && !objects[i])
+ {
+ removed_nil = true;
+ continue;
+ }
+
+ vertex_t* v = vertices_.push ();
+ if (check_success (!vertices_.in_error ()))
+ v->obj = *objects[i];
+ if (!removed_nil) continue;
+ // Fix indices to account for removed nil object.
+ for (auto& l : v->obj.all_links_writer ()) {
+ l.objidx--;
+ }
+ }
+ }
+
+ ~graph_t ()
+ {
+ vertices_.fini ();
+ }
+
+ bool in_error () const
+ {
+ return !successful ||
+ vertices_.in_error () ||
+ num_roots_for_space_.in_error ();
+ }
+
+ const vertex_t& root () const
+ {
+ return vertices_[root_idx ()];
+ }
+
+ unsigned root_idx () const
+ {
+ // Object graphs are in reverse order, the first object is at the end
+ // of the vector. Since the graph is topologically sorted it's safe to
+ // assume the first object has no incoming edges.
+ return vertices_.length - 1;
+ }
+
+ const hb_serialize_context_t::object_t& object(unsigned i) const
+ {
+ return vertices_[i].obj;
+ }
+
+ /*
+ * Generates a new topological sorting of graph ordered by the shortest
+ * distance to each node.
+ */
+ void sort_shortest_distance ()
+ {
+ positions_invalid = true;
+
+ if (vertices_.length <= 1) {
+ // Graph of 1 or less doesn't need sorting.
+ return;
+ }
+
+ update_distances ();
+
+ hb_priority_queue_t queue;
+ 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;
+
+ hb_vector_t<unsigned> removed_edges;
+ if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
+ update_parents ();
+
+ queue.insert (root ().modified_distance (0), root_idx ());
+ int new_id = root_idx ();
+ unsigned order = 1;
+ while (!queue.in_error () && !queue.is_empty ())
+ {
+ unsigned next_id = queue.pop_minimum().second;
+
+ 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 ()) {
+ removed_edges[link.objidx]++;
+ if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
+ // Add the order that the links were encountered to the priority.
+ // This ensures that ties between priorities objects are broken in a consistent
+ // way. More specifically this is set up so that if a set of objects have the same
+ // distance they'll be added to the topological order in the order that they are
+ // referenced from the parent object.
+ queue.insert (vertices_[link.objidx].modified_distance (order++),
+ 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);
+ }
+
+ /*
+ * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
+ */
+ bool assign_32bit_spaces ()
+ {
+ unsigned root_index = root_idx ();
+ hb_set_t visited;
+ hb_set_t roots;
+ for (unsigned i = 0; i <= root_index; i++)
+ {
+ // Only real links can form 32 bit spaces
+ for (auto& l : vertices_[i].obj.real_links)
+ {
+ if (l.width == 4 && !l.is_signed)
+ {
+ roots.add (l.objidx);
+ find_subgraph (l.objidx, visited);
+ }
+ }
+ }
+
+ // Mark everything not in the subgraphs of 32 bit roots as visited.
+ // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs.
+ visited.invert ();
+
+ if (!roots) return false;
+
+ 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);
+ for (unsigned root : connected_roots)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
+ vertices_[root].space = next_space;
+ num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1;
+ distance_invalid = true;
+ positions_invalid = true;
+ }
+
+ // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space
+ // into the 32 bit space as needed, instead of using isolation.
+ }
+
+
+
+ return true;
+ }
+
+ /*
+ * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph
+ * that originate from outside of the subgraph will be removed by duplicating the linked to
+ * object.
+ *
+ * Indices stored in roots will be updated if any of the roots are duplicated to new indices.
+ */
+ bool isolate_subgraph (hb_set_t& roots)
+ {
+ update_parents ();
+ hb_map_t subgraph;
+
+ // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
+ // set the subgraph incoming edge count to match all of root_idx's incoming edges
+ hb_set_t parents;
+ for (unsigned root_idx : roots)
+ {
+ subgraph.set (root_idx, wide_parents (root_idx, parents));
+ find_subgraph (root_idx, subgraph);
+ }
+
+ unsigned original_root_idx = root_idx ();
+ hb_map_t index_map;
+ bool made_changes = false;
+ for (auto entry : subgraph.iter ())
+ {
+ const auto& node = vertices_[entry.first];
+ unsigned subgraph_incoming_edges = entry.second;
+
+ if (subgraph_incoming_edges < node.incoming_edges ())
+ {
+ // Only de-dup objects with incoming links from outside the subgraph.
+ made_changes = true;
+ duplicate_subgraph (entry.first, index_map);
+ }
+ }
+
+ if (!made_changes)
+ return false;
+
+ if (original_root_idx != root_idx ()
+ && parents.has (original_root_idx))
+ {
+ // If the root idx has changed since parents was determined, update root idx in parents
+ parents.add (root_idx ());
+ parents.del (original_root_idx);
+ }
+
+ auto new_subgraph =
+ + subgraph.keys ()
+ | hb_map([&] (unsigned node_idx) {
+ const unsigned *v;
+ if (index_map.has (node_idx, &v)) return *v;
+ return node_idx;
+ })
+ ;
+
+ remap_obj_indices (index_map, new_subgraph);
+ remap_obj_indices (index_map, parents.iter (), true);
+
+ // Update roots set with new indices as needed.
+ unsigned next = HB_SET_VALUE_INVALID;
+ while (roots.next (&next))
+ {
+ const unsigned *v;
+ if (index_map.has (next, &v))
+ {
+ roots.del (next);
+ roots.add (*v);
+ }
+ }
+
+ return true;
+ }
+
+ void find_subgraph (unsigned node_idx, hb_map_t& subgraph)
+ {
+ for (const auto& link : vertices_[node_idx].obj.all_links ())
+ {
+ const unsigned *v;
+ if (subgraph.has (link.objidx, &v))
+ {
+ subgraph.set (link.objidx, *v + 1);
+ continue;
+ }
+ subgraph.set (link.objidx, 1);
+ find_subgraph (link.objidx, subgraph);
+ }
+ }
+
+ void find_subgraph (unsigned node_idx, hb_set_t& subgraph)
+ {
+ if (subgraph.has (node_idx)) return;
+ subgraph.add (node_idx);
+ for (const auto& link : vertices_[node_idx].obj.all_links ())
+ find_subgraph (link.objidx, subgraph);
+ }
+
+ /*
+ * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
+ * links. index_map is updated with mappings from old id to new id. If a duplication has already
+ * been performed for a given index, then it will be skipped.
+ */
+ void duplicate_subgraph (unsigned node_idx, hb_map_t& index_map)
+ {
+ if (index_map.has (node_idx))
+ return;
+
+ index_map.set (node_idx, duplicate (node_idx));
+ for (const auto& l : object (node_idx).all_links ()) {
+ duplicate_subgraph (l.objidx, index_map);
+ }
+ }
+
+ /*
+ * Creates a copy of node_idx and returns it's new index.
+ */
+ unsigned duplicate (unsigned node_idx)
+ {
+ positions_invalid = true;
+ distance_invalid = true;
+
+ auto* clone = vertices_.push ();
+ auto& child = vertices_[node_idx];
+ if (vertices_.in_error ()) {
+ return -1;
+ }
+
+ clone->obj.head = child.obj.head;
+ clone->obj.tail = child.obj.tail;
+ clone->distance = child.distance;
+ clone->space = child.space;
+ clone->parents.reset ();
+
+ unsigned clone_idx = vertices_.length - 2;
+ for (const auto& l : child.obj.real_links)
+ {
+ clone->obj.real_links.push (l);
+ vertices_[l.objidx].parents.push (clone_idx);
+ }
+ for (const auto& l : child.obj.virtual_links)
+ {
+ clone->obj.virtual_links.push (l);
+ vertices_[l.objidx].parents.push (clone_idx);
+ }
+
+ check_success (!clone->obj.real_links.in_error ());
+ check_success (!clone->obj.virtual_links.in_error ());
+
+ // 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.
+ 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 ())
+ vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+
+ return clone_idx;
+ }
+
+ /*
+ * Creates a copy of child and re-assigns the link from
+ * parent to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ */
+ bool duplicate (unsigned parent_idx, unsigned child_idx)
+ {
+ update_parents ();
+
+ unsigned links_to_child = 0;
+ for (const auto& l : vertices_[parent_idx].obj.all_links ())
+ {
+ if (l.objidx == child_idx) links_to_child++;
+ }
+
+ if (vertices_[child_idx].incoming_edges () <= links_to_child)
+ {
+ // Can't duplicate this node, doing so would orphan the original one as all remaining links
+ // to child are from parent.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
+ parent_idx, child_idx);
+ return false;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
+ parent_idx, child_idx);
+
+ unsigned clone_idx = duplicate (child_idx);
+ if (clone_idx == (unsigned) -1) return false;
+ // duplicate shifts the root node idx, so if parent_idx was root update it.
+ if (parent_idx == clone_idx) parent_idx++;
+
+ auto& parent = vertices_[parent_idx];
+ for (auto& l : parent.obj.all_links_writer ())
+ {
+ if (l.objidx != child_idx)
+ continue;
+
+ reassign_link (l, parent_idx, clone_idx);
+ }
+
+ return true;
+ }
+
+ /*
+ * Raises the sorting priority of all children.
+ */
+ bool raise_childrens_priority (unsigned parent_idx)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d",
+ parent_idx);
+ // This operation doesn't change ordering until a sort is run, so no need
+ // to invalidate positions. It does not change graph structure so no need
+ // to update distances or edge counts.
+ auto& parent = vertices_[parent_idx].obj;
+ bool made_change = false;
+ for (auto& l : parent.all_links_writer ())
+ made_change |= vertices_[l.objidx].raise_priority ();
+ return made_change;
+ }
+
+ void print_orphaned_nodes ()
+ {
+ if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+ parents_invalid = true;
+ update_parents();
+
+ for (unsigned i = 0; i < root_idx (); i++)
+ {
+ const auto& v = vertices_[i];
+ if (!v.parents)
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
+ }
+ }
+
+ unsigned num_roots_for_space (unsigned space) const
+ {
+ return num_roots_for_space_[space];
+ }
+
+ unsigned next_space () const
+ {
+ return num_roots_for_space_.length;
+ }
+
+ void move_to_new_space (const hb_set_t& indices)
+ {
+ num_roots_for_space_.push (0);
+ unsigned new_space = num_roots_for_space_.length - 1;
+
+ for (unsigned index : indices) {
+ auto& node = vertices_[index];
+ num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
+ num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
+ node.space = new_space;
+ distance_invalid = true;
+ positions_invalid = true;
+ }
+ }
+
+ unsigned space_for (unsigned index, unsigned* root = nullptr) const
+ {
+ const auto& node = vertices_[index];
+ if (node.space)
+ {
+ if (root != nullptr)
+ *root = index;
+ return node.space;
+ }
+
+ if (!node.parents)
+ {
+ if (root)
+ *root = index;
+ return 0;
+ }
+
+ return space_for (node.parents[0], root);
+ }
+
+ void err_other_error () { this->successful = false; }
+
+ size_t total_size_in_bytes () const {
+ size_t total_size = 0;
+ for (unsigned i = 0; i < vertices_.length; i++) {
+ size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
+ total_size += size;
+ }
+ return total_size;
+ }
+
+
+ private:
+
+ /*
+ * Returns the numbers of incoming edges that are 32bits wide.
+ */
+ unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
+ {
+ unsigned count = 0;
+ hb_set_t visited;
+ for (unsigned p : vertices_[node_idx].parents)
+ {
+ if (visited.has (p)) continue;
+ visited.add (p);
+
+ // Only real links can be wide
+ for (const auto& l : vertices_[p].obj.real_links)
+ {
+ if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
+ {
+ count++;
+ parents.add (p);
+ }
+ }
+ }
+ return count;
+ }
+
+ bool check_success (bool success)
+ { return this->successful && (success || ((void) err_other_error (), false)); }
+
+ public:
+ /*
+ * Creates a map from objid to # of incoming edges.
+ */
+ void update_parents ()
+ {
+ if (!parents_invalid) return;
+
+ for (unsigned i = 0; i < vertices_.length; i++)
+ vertices_[i].parents.reset ();
+
+ for (unsigned p = 0; p < vertices_.length; p++)
+ {
+ for (auto& l : vertices_[p].obj.all_links ())
+ {
+ vertices_[l.objidx].parents.push (p);
+ }
+ }
+
+ parents_invalid = false;
+ }
+
+ /*
+ * compute the serialized start and end positions for each vertex.
+ */
+ void update_positions ()
+ {
+ if (!positions_invalid) return;
+
+ unsigned current_pos = 0;
+ for (int i = root_idx (); i >= 0; i--)
+ {
+ auto& v = vertices_[i];
+ v.start = current_pos;
+ current_pos += v.obj.tail - v.obj.head;
+ v.end = current_pos;
+ }
+
+ positions_invalid = false;
+ }
+
+ /*
+ * Finds the distance to each object in the graph
+ * from the initial node.
+ */
+ void update_distances ()
+ {
+ if (!distance_invalid) return;
+
+ // Uses Dijkstra's algorithm to find all of the shortest distances.
+ // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
+ //
+ // Implementation Note:
+ // Since our priority queue doesn't support fast priority decreases
+ // we instead just add new entries into the queue when a priority changes.
+ // 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 fibonacci queue) with a fast decrease priority.
+ for (unsigned i = 0; i < vertices_.length; i++)
+ {
+ if (i == vertices_.length - 1)
+ vertices_[i].distance = 0;
+ else
+ vertices_[i].distance = hb_int_max (int64_t);
+ }
+
+ hb_priority_queue_t queue;
+ queue.insert (0, vertices_.length - 1);
+
+ hb_vector_t<bool> visited;
+ visited.resize (vertices_.length);
+
+ while (!queue.in_error () && !queue.is_empty ())
+ {
+ unsigned next_idx = queue.pop_minimum ().second;
+ if (visited[next_idx]) continue;
+ const auto& next = vertices_[next_idx];
+ int64_t next_distance = vertices_[next_idx].distance;
+ visited[next_idx] = true;
+
+ for (const auto& link : next.obj.all_links ())
+ {
+ if (visited[link.objidx]) continue;
+
+ const auto& child = vertices_[link.objidx].obj;
+ unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
+ int64_t child_weight = (child.tail - child.head) +
+ ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
+ int64_t child_distance = next_distance + child_weight;
+
+ if (child_distance < vertices_[link.objidx].distance)
+ {
+ vertices_[link.objidx].distance = child_distance;
+ queue.insert (child_distance, link.objidx);
+ }
+ }
+ }
+
+ check_success (!queue.in_error ());
+ if (!check_success (queue.is_empty ()))
+ {
+ print_orphaned_nodes ();
+ return;
+ }
+
+ distance_invalid = false;
+ }
+
+ private:
+ /*
+ * Updates a link in the graph to point to a different object. Corrects the
+ * parents vector on the previous and new child nodes.
+ */
+ void reassign_link (hb_serialize_context_t::object_t::link_t& link,
+ unsigned parent_idx,
+ unsigned new_idx)
+ {
+ unsigned old_idx = link.objidx;
+ link.objidx = new_idx;
+ vertices_[old_idx].remove_parent (parent_idx);
+ vertices_[new_idx].parents.push (parent_idx);
+ }
+
+ /*
+ * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
+ */
+ template<typename Iterator, hb_requires (hb_is_iterator (Iterator))>
+ void remap_obj_indices (const hb_map_t& id_map,
+ Iterator subgraph,
+ bool only_wide = false)
+ {
+ if (!id_map) return;
+ for (unsigned i : subgraph)
+ {
+ for (auto& link : vertices_[i].obj.all_links_writer ())
+ {
+ const unsigned *v;
+ if (!id_map.has (link.objidx, &v)) continue;
+ if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
+
+ reassign_link (link, i, *v);
+ }
+ }
+ }
+
+ /*
+ * Updates all objidx's in all links using the provided mapping.
+ */
+ void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
+ hb_vector_t<vertex_t>* sorted_graph) const
+ {
+ for (unsigned i = 0; i < sorted_graph->length; i++)
+ {
+ (*sorted_graph)[i].remap_parents (id_map);
+ for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
+ {
+ link.objidx = id_map[link.objidx];
+ }
+ }
+ }
+
+ /*
+ * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
+ * For this search the graph is treated as being undirected.
+ *
+ * Connected targets will be added to connected and removed from targets. All visited nodes
+ * will be added to visited.
+ */
+ void find_connected_nodes (unsigned start_idx,
+ hb_set_t& targets,
+ 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);
+
+ if (targets.has (start_idx))
+ {
+ targets.del (start_idx);
+ connected.add (start_idx);
+ }
+
+ const auto& v = vertices_[start_idx];
+
+ // Graph is treated as undirected so search children and parents of start_idx
+ for (const auto& l : v.obj.all_links ())
+ find_connected_nodes (l.objidx, targets, visited, connected);
+
+ for (unsigned p : v.parents)
+ find_connected_nodes (p, targets, visited, connected);
+ }
+
+ 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;
+ bool positions_invalid;
+ bool successful;
+ hb_vector_t<unsigned> num_roots_for_space_;
+};
+
+}
+
+#endif // GRAPH_GRAPH_HH
diff --git a/thirdparty/harfbuzz/src/graph/serialize.hh b/thirdparty/harfbuzz/src/graph/serialize.hh
new file mode 100644
index 0000000000..ecc6cc5aea
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/serialize.hh
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_SERIALIZE_HH
+#define GRAPH_SERIALIZE_HH
+
+namespace graph {
+
+struct overflow_record_t
+{
+ unsigned parent;
+ unsigned child;
+};
+
+inline
+int64_t compute_offset (
+ const graph_t& graph,
+ unsigned parent_idx,
+ const hb_serialize_context_t::object_t::link_t& link)
+{
+ const auto& parent = graph.vertices_[parent_idx];
+ const auto& child = graph.vertices_[link.objidx];
+ int64_t offset = 0;
+ switch ((hb_serialize_context_t::whence_t) link.whence) {
+ case hb_serialize_context_t::whence_t::Head:
+ offset = child.start - parent.start; break;
+ case hb_serialize_context_t::whence_t::Tail:
+ offset = child.start - parent.end; break;
+ case hb_serialize_context_t::whence_t::Absolute:
+ offset = child.start; break;
+ }
+
+ assert (offset >= link.bias);
+ offset -= link.bias;
+ return offset;
+}
+
+inline
+bool is_valid_offset (int64_t offset,
+ const hb_serialize_context_t::object_t::link_t& link)
+{
+ if (unlikely (!link.width))
+ // Virtual links can't overflow.
+ return link.is_signed || offset >= 0;
+
+ if (link.is_signed)
+ {
+ if (link.width == 4)
+ return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
+ else
+ return offset >= -(1 << 15) && offset < (1 << 15);
+ }
+ else
+ {
+ if (link.width == 4)
+ return offset >= 0 && offset < ((int64_t) 1 << 32);
+ else if (link.width == 3)
+ return offset >= 0 && offset < ((int32_t) 1 << 24);
+ else
+ return offset >= 0 && offset < (1 << 16);
+ }
+}
+
+/*
+ * Will any offsets overflow on graph when it's serialized?
+ */
+inline bool
+will_overflow (graph_t& graph,
+ hb_vector_t<overflow_record_t>* overflows = nullptr)
+{
+ if (overflows) overflows->resize (0);
+ graph.update_positions ();
+
+ const auto& vertices = graph.vertices_;
+ for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
+ {
+ // Don't need to check virtual links for overflow
+ for (const auto& link : vertices[parent_idx].obj.real_links)
+ {
+ int64_t offset = compute_offset (graph, parent_idx, link);
+ if (is_valid_offset (offset, link))
+ continue;
+
+ if (!overflows) return true;
+
+ overflow_record_t r;
+ r.parent = parent_idx;
+ r.child = link.objidx;
+ overflows->push (r);
+ }
+ }
+
+ if (!overflows) return false;
+ return overflows->length;
+}
+
+inline
+void print_overflows (graph_t& graph,
+ const hb_vector_t<overflow_record_t>& overflows)
+{
+ if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
+
+ graph.update_parents ();
+ int limit = 10;
+ for (const auto& o : overflows)
+ {
+ if (!limit--) break;
+ const auto& parent = graph.vertices_[o.parent];
+ const auto& child = graph.vertices_[o.child];
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " overflow from "
+ "%4d (%4d in, %4d out, space %2d) => "
+ "%4d (%4d in, %4d out, space %2d)",
+ o.parent,
+ parent.incoming_edges (),
+ parent.obj.real_links.length + parent.obj.virtual_links.length,
+ graph.space_for (o.parent),
+ o.child,
+ child.incoming_edges (),
+ child.obj.real_links.length + child.obj.virtual_links.length,
+ graph.space_for (o.child));
+ }
+ if (overflows.length > 10) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10);
+ }
+}
+
+template <typename O> inline void
+serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
+ char* head,
+ hb_serialize_context_t* c)
+{
+ OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
+ *offset = 0;
+ c->add_link (*offset,
+ // serializer has an extra nil object at the start of the
+ // object array. So all id's are +1 of what our id's are.
+ link.objidx + 1,
+ (hb_serialize_context_t::whence_t) link.whence,
+ link.bias);
+}
+
+inline
+void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
+ char* head,
+ hb_serialize_context_t* c)
+{
+ switch (link.width)
+ {
+ case 0:
+ // Virtual links aren't serialized.
+ return;
+ case 4:
+ if (link.is_signed)
+ {
+ serialize_link_of_type<OT::HBINT32> (link, head, c);
+ } else {
+ serialize_link_of_type<OT::HBUINT32> (link, head, c);
+ }
+ return;
+ case 2:
+ if (link.is_signed)
+ {
+ serialize_link_of_type<OT::HBINT16> (link, head, c);
+ } else {
+ serialize_link_of_type<OT::HBUINT16> (link, head, c);
+ }
+ return;
+ case 3:
+ serialize_link_of_type<OT::HBUINT24> (link, head, c);
+ return;
+ default:
+ // Unexpected link width.
+ assert (0);
+ }
+}
+
+/*
+ * serialize graph into the provided serialization buffer.
+ */
+inline hb_blob_t* serialize (const graph_t& graph)
+{
+ hb_vector_t<char> buffer;
+ size_t size = graph.total_size_in_bytes ();
+ if (!buffer.alloc (size)) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
+ return nullptr;
+ }
+ hb_serialize_context_t c((void *) buffer, size);
+
+ c.start_serialize<void> ();
+ const auto& vertices = graph.vertices_;
+ for (unsigned i = 0; i < vertices.length; i++) {
+ c.push ();
+
+ size_t size = vertices[i].obj.tail - vertices[i].obj.head;
+ char* start = c.allocate_size <char> (size);
+ if (!start) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
+ return nullptr;
+ }
+
+ memcpy (start, vertices[i].obj.head, size);
+
+ // Only real links needs to be serialized.
+ for (const auto& link : vertices[i].obj.real_links)
+ serialize_link (link, start, &c);
+
+ // All duplications are already encoded in the graph, so don't
+ // enable sharing during packing.
+ c.pop_pack (false);
+ }
+ c.end_serialize ();
+
+ if (c.in_error ()) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
+ c.errors);
+ return nullptr;
+ }
+
+ return c.copy_blob ();
+}
+
+} // namespace graph
+
+#endif // GRAPH_SERIALIZE_HH
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
index 0354b47d5a..6a24c90c31 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
@@ -287,7 +287,7 @@ struct KerxSubTableFormat1
* in the 'kern' table example. */
if (v == -0x8000)
{
- o.attach_type() = ATTACH_TYPE_NONE;
+ o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.y_offset = 0;
}
@@ -310,7 +310,7 @@ struct KerxSubTableFormat1
/* CoreText doesn't do crossStream kerning in vertical. We do. */
if (v == -0x8000)
{
- o.attach_type() = ATTACH_TYPE_NONE;
+ o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.x_offset = 0;
}
@@ -567,7 +567,7 @@ struct KerxSubTableFormat4
}
break;
}
- o.attach_type() = ATTACH_TYPE_MARK;
+ o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
o.attach_chain() = (int) mark - (int) buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
@@ -901,7 +901,7 @@ struct KerxTable
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
{
- pos[i].attach_type() = ATTACH_TYPE_CURSIVE;
+ pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
/* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
* since there needs to be a non-zero attachment for post-positioning 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..3d053cb13e 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -123,7 +123,7 @@ struct RearrangementSubtable
bool reverse_l = 3 == (m >> 4);
bool reverse_r = 3 == (m & 0x0F);
- if (end - start >= l + r)
+ if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
{
buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
buffer->merge_clusters (start, end);
@@ -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-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index c40a55cd1f..f1633d886a 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -59,7 +59,7 @@
static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
- static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
+ static inline constexpr unsigned operator ~ (T r) { return (~(unsigned) r); } \
static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
@@ -150,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];
};
@@ -211,31 +227,26 @@ struct
}
HB_FUNCOBJ (hb_bool);
-template <typename T>
-static inline
-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
-T hb_coerce (const V v) { return *v; }
-
struct
{
private:
template <typename T> constexpr auto
- impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+ impl (const T& v, hb_priority<1>) 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> constexpr uint32_t
+ impl (const hb::shared_ptr<T>& v, hb_priority<1>) const
+ {
+ return v.get () ? v.get ()->hash () : 0;
+ }
+ template <typename T> constexpr uint32_t
+ impl (const hb::unique_ptr<T>& v, hb_priority<1>) const
+ {
+ return v.get () ? v.get ()->hash () : 0;
+ }
- template <typename T,
- hb_enable_if (std::is_integral<T>::value)> constexpr auto
- impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
- (
- /* Knuth's multiplicative method: */
- (uint32_t) v * 2654435761u
- )
+ template <typename T> constexpr auto
+ impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
public:
@@ -846,6 +857,11 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
{
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
}
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4)
+{
+ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4);
+}
/*
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 1d1476d7cd..5baeb6f7fe 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -56,7 +56,6 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
hb_array_t& operator= (const hb_array_t&) = default;
hb_array_t& operator= (hb_array_t&&) = default;
- constexpr hb_array_t (std::nullptr_t) : hb_array_t () {}
constexpr hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
template <unsigned int length_>
constexpr hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {}
@@ -314,7 +313,6 @@ struct hb_sorted_array_t :
hb_sorted_array_t& operator= (const hb_sorted_array_t&) = default;
hb_sorted_array_t& operator= (hb_sorted_array_t&&) = default;
- constexpr hb_sorted_array_t (std::nullptr_t) : hb_sorted_array_t () {}
constexpr hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
template <unsigned int length_>
constexpr hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
@@ -346,7 +344,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 +382,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 +402,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 +410,18 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
}
return true;
}
-
-/* TODO Specialize operator== 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 +430,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 a9e1278de7..8e8c988716 100644
--- a/thirdparty/harfbuzz/src/hb-bimap.hh
+++ b/thirdparty/harfbuzz/src/hb-bimap.hh
@@ -39,6 +39,12 @@ struct hb_bimap_t
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)
@@ -48,17 +54,18 @@ struct hb_bimap_t
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
forw_map.set (lhs, rhs);
- if (in_error ()) return;
+ if (unlikely (in_error ())) return;
back_map.set (rhs, lhs);
- if (in_error ()) forw_map.del (lhs);
+ if (unlikely (in_error ())) forw_map.del (lhs);
}
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
- bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
+ bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
void del (hb_codepoint_t lhs)
{
@@ -72,7 +79,7 @@ struct hb_bimap_t
back_map.clear ();
}
- bool is_empty () const { return get_population () == 0; }
+ bool is_empty () const { return forw_map.is_empty (); }
unsigned int get_population () const { return forw_map.get_population (); }
diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh
index 9759836654..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); }
diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
index 4a4ce34053..27fb0732ea 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 () ^ (uint32_t) inverted; }
+
hb_codepoint_t get_min () const
{
hb_codepoint_t v = INVALID;
@@ -97,7 +100,7 @@ struct hb_bit_set_invertible_t
void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
- { return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
+ { return unlikely (inverted) ? ((void) s.del_range (a, b), true) : s.add_range (a, b); }
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh
index fcaff9f3be..438fb66a2c 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set.hh
@@ -56,7 +56,7 @@ struct hb_bit_set_t
{
successful = true;
population = 0;
- last_page_lookup = 0;
+ last_page_lookup.set_relaxed (0);
page_map.init ();
pages.init ();
}
@@ -78,7 +78,7 @@ struct hb_bit_set_t
bool successful = true; /* Allocations successful */
mutable unsigned int population = 0;
- mutable unsigned int last_page_lookup = 0;
+ mutable hb_atomic_int_t last_page_lookup = 0;
hb_sorted_vector_t<page_map_t> page_map;
hb_vector_t<page_t> pages;
@@ -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:
@@ -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;
@@ -593,7 +607,7 @@ struct hb_bit_set_t
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (*codepoint);
- unsigned int i = last_page_lookup;
+ unsigned int i = last_page_lookup.get_relaxed ();
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
@@ -611,7 +625,7 @@ struct hb_bit_set_t
if (pages_array[current.index].next (codepoint))
{
*codepoint += current.major * page_t::PAGE_BITS;
- last_page_lookup = i;
+ last_page_lookup.set_relaxed (i);
return true;
}
i++;
@@ -624,11 +638,11 @@ struct hb_bit_set_t
if (m != INVALID)
{
*codepoint = current.major * page_t::PAGE_BITS + m;
- last_page_lookup = i;
+ last_page_lookup.set_relaxed (i);
return true;
}
}
- last_page_lookup = 0;
+ last_page_lookup.set_relaxed (0);
*codepoint = INVALID;
return false;
}
@@ -711,7 +725,7 @@ struct hb_bit_set_t
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
- unsigned int i = last_page_lookup;
+ unsigned int i = last_page_lookup.get_relaxed ();
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
@@ -752,7 +766,7 @@ struct hb_bit_set_t
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
- unsigned int i = last_page_lookup;
+ unsigned int i = last_page_lookup.get_relaxed ();
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
@@ -874,8 +888,20 @@ 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 int i;
+ 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... */
+ unsigned i = last_page_lookup.get_relaxed ();
+ if (likely (i < page_map.length))
+ {
+ auto &cached_page = page_map.arrayZ[i];
+ if (cached_page.major == major)
+ return &pages[cached_page.index];
+ }
+
+ page_map_t map = {major, pages.length};
if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
{
if (!insert)
@@ -890,15 +916,31 @@ struct hb_bit_set_t
(page_map.length - 1 - i) * page_map.item_size);
page_map[i] = map;
}
+
+ last_page_lookup.set_relaxed (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... */
+ unsigned i = last_page_lookup.get_relaxed ();
+ if (likely (i < page_map.length))
+ {
+ auto &cached_page = page_map.arrayZ[i];
+ if (cached_page.major == major)
+ return &pages[cached_page.index];
+ }
+
+ page_map_t key = {major};
+ if (!page_map.bfind (key, &i))
+ return nullptr;
+
+ last_page_lookup.set_relaxed (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]; }
diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc
index f120002d17..b561a9374e 100644
--- a/thirdparty/harfbuzz/src/hb-blob.cc
+++ b/thirdparty/harfbuzz/src/hb-blob.cc
@@ -369,7 +369,7 @@ hb_blob_get_length (hb_blob_t *blob)
*
* Fetches the data from a blob.
*
- * Returns: (transfer none) (array length=length): the byte data of @blob.
+ * Returns: (nullable) (transfer none) (array length=length): the byte data of @blob.
*
* Since: 0.9.2
**/
@@ -572,7 +572,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
strncpy (rsrc_name, file_name, name_len);
strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
- sizeof (_PATH_RSRCFORKSPEC) - 1);
+ sizeof (_PATH_RSRCFORKSPEC));
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
hb_free (rsrc_name);
@@ -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-serialize.cc b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
index 6539b89640..3f619a113e 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
@@ -31,7 +31,7 @@
#include "hb-buffer.hh"
-static const char *serialize_formats[] = {
+static const char *_hb_buffer_serialize_formats[] = {
"text",
"json",
nullptr
@@ -50,7 +50,7 @@ static const char *serialize_formats[] = {
const char **
hb_buffer_serialize_list_formats ()
{
- return serialize_formats;
+ return _hb_buffer_serialize_formats;
}
/**
@@ -91,8 +91,8 @@ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
{
switch ((unsigned) format)
{
- case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
- case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
+ case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_formats[0];
+ case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_formats[1];
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr;
}
@@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
* @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- * read glyph names and extents. If %NULL, and empty font will be used.
+ * read glyph names and extents. If %NULL, an empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
* to serialize.
@@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
* to serialize.
@@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
* @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- * read glyph names and extents. If %NULL, and empty font will be used.
+ * read glyph names and extents. If %NULL, an empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
* to serialize.
diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
index dea2c11c35..5453e1ca94 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-verify.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
@@ -102,9 +102,9 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
/* 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_set_flags (fragment, (hb_buffer_flags_t (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);
+ hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (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);
@@ -169,6 +169,12 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_destroy (fragment);
return false;
}
+ else if (!fragment->successful || fragment->shaping_failed)
+ {
+ hb_buffer_destroy (reconstruction);
+ hb_buffer_destroy (fragment);
+ return true;
+ }
hb_buffer_append (reconstruction, fragment, 0, -1);
start = end;
@@ -238,10 +244,10 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
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_set_flags (fragments[0], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY)));
+ hb_buffer_set_flags (fragments[1], (hb_buffer_flags_t (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_buffer_set_flags (reconstruction, (hb_buffer_flags_t (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);
@@ -317,12 +323,22 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
ret = false;
goto out;
}
+ else if (!fragments[0]->successful || fragments[0]->shaping_failed)
+ {
+ ret = true;
+ 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;
}
+ else if (!fragments[1]->successful || fragments[1]->shaping_failed)
+ {
+ ret = true;
+ goto out;
+ }
if (!forward)
{
@@ -402,6 +418,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer,
ret = false;
if (!ret)
{
+#ifndef HB_NO_BUFFER_SERIALIZE
unsigned len = text_buffer->len;
hb_vector_t<char> bytes;
if (likely (bytes.resize (len * 10 + 16)))
@@ -414,6 +431,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
}
+#endif
}
return ret;
}
diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc
index 6a9ee3ccc8..2272ecf09b 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer.cc
@@ -81,8 +81,8 @@ hb_segment_properties_equal (const hb_segment_properties_t *a,
unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p)
{
- return (unsigned int) p->direction ^
- (unsigned int) p->script ^
+ return ((unsigned int) p->direction * 31 +
+ (unsigned int) p->script) * 31 +
(intptr_t) (p->language);
}
@@ -289,6 +289,7 @@ hb_buffer_t::clear ()
props = default_props;
successful = true;
+ shaping_failed = false;
have_output = false;
have_positions = false;
@@ -310,6 +311,7 @@ hb_buffer_t::enter ()
{
deallocate_var_all ();
serial = 0;
+ shaping_failed = false;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR)))
{
@@ -329,6 +331,7 @@ hb_buffer_t::leave ()
max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
deallocate_var_all ();
serial = 0;
+ // Intentionally not reseting shaping_failed, such that it can be inspected.
}
@@ -542,7 +545,8 @@ hb_buffer_t::delete_glyph ()
/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
unsigned int cluster = info[idx].cluster;
- if (idx + 1 < len && cluster == info[idx + 1].cluster)
+ if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||
+ (out_len && cluster == out_info[out_len - 1].cluster))
{
/* Cluster survives; do nothing. */
goto done;
@@ -623,6 +627,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_SEGMENT_PROPERTIES_DEFAULT,
false, /* successful */
+ true, /* shaping_failed */
false, /* have_output */
true /* have_positions */
@@ -631,7 +636,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
/**
- * hb_buffer_create: (Xconstructor)
+ * hb_buffer_create:
*
* Creates a new #hb_buffer_t with all properties to defaults.
*
@@ -834,7 +839,7 @@ hb_buffer_set_content_type (hb_buffer_t *buffer,
* Since: 0.9.5
**/
hb_buffer_content_type_t
-hb_buffer_get_content_type (hb_buffer_t *buffer)
+hb_buffer_get_content_type (const hb_buffer_t *buffer)
{
return buffer->content_type;
}
@@ -876,7 +881,7 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
* Since: 0.9.2
**/
hb_unicode_funcs_t *
-hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
+hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)
{
return buffer->unicode;
}
@@ -919,7 +924,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
* Since: 0.9.2
**/
hb_direction_t
-hb_buffer_get_direction (hb_buffer_t *buffer)
+hb_buffer_get_direction (const hb_buffer_t *buffer)
{
return buffer->props.direction;
}
@@ -963,7 +968,7 @@ hb_buffer_set_script (hb_buffer_t *buffer,
* Since: 0.9.2
**/
hb_script_t
-hb_buffer_get_script (hb_buffer_t *buffer)
+hb_buffer_get_script (const hb_buffer_t *buffer)
{
return buffer->props.script;
}
@@ -1007,7 +1012,7 @@ hb_buffer_set_language (hb_buffer_t *buffer,
* Since: 0.9.2
**/
hb_language_t
-hb_buffer_get_language (hb_buffer_t *buffer)
+hb_buffer_get_language (const hb_buffer_t *buffer)
{
return buffer->props.language;
}
@@ -1043,7 +1048,7 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
* Since: 0.9.7
**/
void
-hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
hb_segment_properties_t *props)
{
*props = buffer->props;
@@ -1081,7 +1086,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
* Since: 0.9.7
**/
hb_buffer_flags_t
-hb_buffer_get_flags (hb_buffer_t *buffer)
+hb_buffer_get_flags (const hb_buffer_t *buffer)
{
return buffer->flags;
}
@@ -1120,7 +1125,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
* Since: 0.9.42
**/
hb_buffer_cluster_level_t
-hb_buffer_get_cluster_level (hb_buffer_t *buffer)
+hb_buffer_get_cluster_level (const hb_buffer_t *buffer)
{
return buffer->cluster_level;
}
@@ -1161,7 +1166,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
* Since: 0.9.31
**/
hb_codepoint_t
-hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
+hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)
{
return buffer->replacement;
}
@@ -1201,7 +1206,7 @@ hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
* Since: 2.0.0
**/
hb_codepoint_t
-hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
+hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
{
return buffer->invisible;
}
@@ -1241,7 +1246,7 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
* Since: 3.1.0
**/
hb_codepoint_t
-hb_buffer_get_not_found_glyph (hb_buffer_t *buffer)
+hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
{
return buffer->not_found;
}
@@ -1381,7 +1386,7 @@ hb_buffer_set_length (hb_buffer_t *buffer,
* Since: 0.9.2
**/
unsigned int
-hb_buffer_get_length (hb_buffer_t *buffer)
+hb_buffer_get_length (const hb_buffer_t *buffer)
{
return buffer->len;
}
diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h
index 14aaa5e1f5..22fb3496f2 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.h
+++ b/thirdparty/harfbuzz/src/hb-buffer.h
@@ -289,7 +289,7 @@ hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type);
HB_EXTERN hb_buffer_content_type_t
-hb_buffer_get_content_type (hb_buffer_t *buffer);
+hb_buffer_get_content_type (const hb_buffer_t *buffer);
HB_EXTERN void
@@ -297,21 +297,21 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs);
HB_EXTERN hb_unicode_funcs_t *
-hb_buffer_get_unicode_funcs (hb_buffer_t *buffer);
+hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction);
HB_EXTERN hb_direction_t
-hb_buffer_get_direction (hb_buffer_t *buffer);
+hb_buffer_get_direction (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script);
HB_EXTERN hb_script_t
-hb_buffer_get_script (hb_buffer_t *buffer);
+hb_buffer_get_script (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_language (hb_buffer_t *buffer,
@@ -319,14 +319,14 @@ hb_buffer_set_language (hb_buffer_t *buffer,
HB_EXTERN hb_language_t
-hb_buffer_get_language (hb_buffer_t *buffer);
+hb_buffer_get_language (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props);
HB_EXTERN void
-hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
hb_segment_properties_t *props);
HB_EXTERN void
@@ -373,6 +373,7 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* 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
+ * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
*
* Flags for #hb_buffer_t.
*
@@ -386,7 +387,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
HB_BUFFER_FLAG_VERIFY = 0x00000020u,
- HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u
+ HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u,
+
+ HB_BUFFER_FLAG_DEFINED = 0x0000007Fu
} hb_buffer_flags_t;
HB_EXTERN void
@@ -394,7 +397,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags);
HB_EXTERN hb_buffer_flags_t
-hb_buffer_get_flags (hb_buffer_t *buffer);
+hb_buffer_get_flags (const hb_buffer_t *buffer);
/**
* hb_buffer_cluster_level_t:
@@ -436,7 +439,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);
HB_EXTERN hb_buffer_cluster_level_t
-hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+hb_buffer_get_cluster_level (const hb_buffer_t *buffer);
/**
* HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
@@ -453,21 +456,21 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement);
HB_EXTERN hb_codepoint_t
-hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
+hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
hb_codepoint_t invisible);
HB_EXTERN hb_codepoint_t
-hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
+hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
hb_codepoint_t not_found);
HB_EXTERN hb_codepoint_t
-hb_buffer_get_not_found_glyph (hb_buffer_t *buffer);
+hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
/*
@@ -549,7 +552,7 @@ hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length);
HB_EXTERN unsigned int
-hb_buffer_get_length (hb_buffer_t *buffer);
+hb_buffer_get_length (const hb_buffer_t *buffer);
/* Getting glyphs out of the buffer */
@@ -583,6 +586,7 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
* @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
* glyph offsets will reflect absolute glyph positions. Since: 1.8.0
+ * @HB_BUFFER_SERIALIZE_FLAG_DEFINED: All currently defined flags. Since: 4.4.0
*
* Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
*
@@ -595,7 +599,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u,
- HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u
+ HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u,
+
+ HB_BUFFER_SERIALIZE_FLAG_DEFINED = 0x0000003Fu
} hb_buffer_serialize_flags_t;
/**
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index bc6992905e..6ca78f28d4 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -57,6 +57,7 @@
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
+HB_MARK_AS_FLAG_T (hb_glyph_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
@@ -69,12 +70,13 @@ enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u,
- /* Reserved for complex shapers' internal use. */
- HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
- HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
- HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
- HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
+ /* Reserved for shapers' internal use. */
+ HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u,
+ HB_BUFFER_SCRATCH_FLAG_SHAPER1 = 0x02000000u,
+ HB_BUFFER_SCRATCH_FLAG_SHAPER2 = 0x04000000u,
+ HB_BUFFER_SCRATCH_FLAG_SHAPER3 = 0x08000000u,
};
HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
@@ -106,6 +108,7 @@ struct hb_buffer_t
hb_segment_properties_t props; /* Script, language, direction */
bool successful; /* Allocations successful */
+ bool shaping_failed; /* Shaping failure */
bool have_output; /* Whether we have an output buffer going on */
bool have_positions; /* Whether we have positions */
@@ -130,9 +133,7 @@ struct hb_buffer_t
* 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. */
@@ -161,38 +162,40 @@ struct hb_buffer_t
void allocate_var (unsigned int start, unsigned int count)
{
-#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (0 == (allocated_var_bits & bits));
allocated_var_bits |= bits;
-#endif
+ }
+ bool try_allocate_var (unsigned int start, unsigned int count)
+ {
+ unsigned int end = start + count;
+ assert (end <= 8);
+ unsigned int bits = (1u<<end) - (1u<<start);
+ if (allocated_var_bits & bits)
+ return false;
+ allocated_var_bits |= bits;
+ return true;
}
void deallocate_var (unsigned int start, unsigned int count)
{
-#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
allocated_var_bits &= ~bits;
-#endif
}
void assert_var (unsigned int start, unsigned int count)
{
-#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
- unsigned int bits = (1u<<end) - (1u<<start);
+ HB_UNUSED unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
-#endif
}
void deallocate_var_all ()
{
-#ifndef HB_NDEBUG
allocated_var_bits = 0;
-#endif
}
hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
@@ -549,7 +552,7 @@ struct hb_buffer_t
#ifdef HB_NO_BUFFER_MESSAGE
return true;
#else
- if (!messaging ())
+ if (likely (!messaging ()))
return true;
message_depth++;
@@ -619,9 +622,10 @@ DECLARE_NULL_INSTANCE (hb_buffer_t);
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
sizeof (b->info[0].var))
-#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ())
-#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
-#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
+#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ())
+#define HB_BUFFER_TRY_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, try_allocate_var, var ())
+#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
+#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
#endif /* HB_BUFFER_HH */
diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh
index e617b75de9..d6b229ed65 100644
--- a/thirdparty/harfbuzz/src/hb-cache.hh
+++ b/thirdparty/harfbuzz/src/hb-cache.hh
@@ -32,7 +32,7 @@
/* Implements a lockfree cache for int->int functions. */
-template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
+template <unsigned int key_bits=16, unsigned int value_bits=8 + 32 - key_bits, unsigned int cache_bits=8>
struct hb_cache_t
{
static_assert ((key_bits >= cache_bits), "");
diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
index 641de0eff2..5c2cb060a4 100644
--- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
+++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
@@ -248,6 +248,9 @@ struct number_t
/* 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)
@@ -274,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
{
@@ -308,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_;
@@ -334,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)))
@@ -358,44 +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);
- }
- void fini () { elements.fini (); }
-
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
{
@@ -424,7 +399,7 @@ struct cff_stack_t
const ELEM& peek ()
{
- if (unlikely (count < 0))
+ if (unlikely (count == 0))
{
set_error ();
return Null (ELEM);
@@ -434,7 +409,7 @@ struct cff_stack_t
void unpop ()
{
- if (likely (count < elements.length))
+ if (likely (count < LIMIT))
count++;
else
set_error ();
@@ -442,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 */
@@ -508,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;
};
@@ -518,8 +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
{
+ hb_ubytes_t str;
op_code_t op;
- byte_str_t str;
};
/* base of OP_SERIALIZER */
@@ -547,11 +520,16 @@ struct parsed_values_t
}
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;
}
@@ -559,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;
}
@@ -581,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 (); }
@@ -622,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
@@ -668,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 ef299369b5..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];
}
@@ -112,10 +112,9 @@ 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;
@@ -123,15 +122,11 @@ struct cs_interp_env_t : interp_env_t<ARG>
vstem_count = 0;
hintmask_size = 0;
pt.set_int (0, 0);
- callStack.init ();
globalSubrs.init (globalSubrs_);
localSubrs.init (localSubrs_);
}
- void fini ()
+ ~cs_interp_env_t ()
{
- interp_env_t<ARG>::fini ();
-
- callStack.fini ();
globalSubrs.fini ();
localSubrs.fini ();
}
@@ -880,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 766183760e..d0b9e7b086 100644
--- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
+++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
@@ -64,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;
@@ -100,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 ()
@@ -122,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);
@@ -133,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
{
@@ -151,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:
@@ -180,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 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;
@@ -204,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;
@@ -217,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;
@@ -234,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 41229b9183..7266d9b01f 100644
--- a/thirdparty/harfbuzz/src/hb-common.cc
+++ b/thirdparty/harfbuzz/src/hb-common.cc
@@ -160,7 +160,7 @@ hb_tag_to_string (hb_tag_t tag, char *buf)
/* hb_direction_t */
-const char direction_strings[][4] = {
+static const char direction_strings[][4] = {
"ltr",
"rtl",
"ttb",
diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh
index 4b46dea938..2578231d23 100644
--- a/thirdparty/harfbuzz/src/hb-config.hh
+++ b/thirdparty/harfbuzz/src/hb-config.hh
@@ -64,6 +64,7 @@
#define HB_NO_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
#define HB_NO_HINTING
+#define HB_NO_LANGUAGE_LONG
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
@@ -145,10 +146,10 @@
#endif
#ifdef HB_NO_OT_SHAPE_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#define HB_NO_OT_SHAPER_ARABIC_FALLBACK
+#define HB_NO_OT_SHAPER_HEBREW_FALLBACK
+#define HB_NO_OT_SHAPER_THAI_FALLBACK
+#define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS
#endif
#ifdef NDEBUG
@@ -163,5 +164,9 @@
#endif
#endif
+#ifdef HB_OPTIMIZE_SIZE
+#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#endif
+
#endif /* HB_CONFIG_HH */
diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc
index 6ccc1b0a2b..99b33c001e 100644
--- a/thirdparty/harfbuzz/src/hb-coretext.cc
+++ b/thirdparty/harfbuzz/src/hb-coretext.cc
@@ -332,7 +332,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
return nullptr;
}
- if (font->coords)
+ if (font->num_coords)
{
CFMutableDictionaryRef variations =
CFDictionaryCreateMutable (kCFAllocatorDefault,
@@ -379,37 +379,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
CFRelease ((CTFontRef) data);
}
-static const hb_coretext_font_data_t *
-hb_coretext_font_data_sync (hb_font_t *font)
-{
-retry:
- const hb_coretext_font_data_t *data = font->data.coretext;
- if (unlikely (!data)) return nullptr;
-
- if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5)
- {
- /* XXX-MT-bug
- * Note that evaluating condition above can be dangerous if another thread
- * got here first and destructed data. That's, as always, bad use pattern.
- * If you modify the font (change font size), other threads must not be
- * using it at the same time. However, since this check is delayed to
- * when one actually tries to shape something, this is a XXX race condition
- * (and the only one we have that I know of) right now. Ie. you modify the
- * font size in one thread, then (supposedly safely) try to use it from two
- * or more threads and BOOM! I'm not sure how to fix this. We want RCU.
- */
-
- /* Drop and recreate. */
- /* If someone dropped it in the mean time, throw it away and don't touch it.
- * Otherwise, destruct it. */
- if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr)))
- _hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data));
- else
- goto retry;
- }
- return font->data.coretext;
-}
-
/**
* hb_coretext_font_create:
* @ct_font: The CTFontRef to work upon
@@ -455,8 +424,8 @@ hb_coretext_font_create (CTFontRef ct_font)
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
- const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font);
- return data ? (CTFontRef) data : nullptr;
+ CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+ return ct_font ? (CTFontRef) ct_font : nullptr;
}
@@ -516,7 +485,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
{
hb_face_t *face = font->face;
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
- CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font);
+ CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -1106,7 +1075,8 @@ resize_and_retry:
advance = positions[j + 1].x - positions[j].x;
else /* last glyph */
advance = run_advance - (positions[j].x - positions[0].x);
- info->mask = round (advance * x_mult);
+ /* int cast necessary to pass through negative values. */
+ info->mask = (int) round (advance * x_mult);
info->var1.i32 = x_offset;
info->var2.i32 = round (positions[j].y * y_mult);
info++;
@@ -1122,7 +1092,8 @@ resize_and_retry:
advance = positions[j + 1].y - positions[j].y;
else /* last glyph */
advance = run_advance - (positions[j].y - positions[0].y);
- info->mask = round (advance * y_mult);
+ /* int cast necessary to pass through negative values. */
+ info->mask = (int) round (advance * y_mult);
info->var1.i32 = round (positions[j].x * x_mult);
info->var2.i32 = y_offset;
info++;
@@ -1151,7 +1122,7 @@ resize_and_retry:
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
- info++, pos++;
+ info++; pos++;
}
else
for (unsigned int i = 0; i < count; i++)
@@ -1160,7 +1131,7 @@ resize_and_retry:
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
- info++, pos++;
+ info++; pos++;
}
/* Fix up clusters so that we never return out-of-order indices;
@@ -1173,7 +1144,8 @@ resize_and_retry:
* This does *not* mean we'll form the same clusters as Uniscribe
* or the native OT backend, only that the cluster indices will be
* monotonic in the output buffer. */
- if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
+ if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
+ buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
hb_glyph_info_t *info = buffer->info;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
@@ -1197,6 +1169,10 @@ resize_and_retry:
}
}
+ /* TODO: Sometimes the above positioning code generates negative
+ * advance values. Fix them up. Example, with NotoNastaliqUrdu
+ * font and sequence ابهد. */
+
buffer->clear_glyph_flags ();
buffer->unsafe_to_break ();
diff --git a/thirdparty/harfbuzz/src/hb-cplusplus.hh b/thirdparty/harfbuzz/src/hb-cplusplus.hh
new file mode 100644
index 0000000000..86d0452080
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-cplusplus.hh
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#ifndef HB_CPLUSPLUS_HH
+#define HB_CPLUSPLUS_HH
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+HB_END_DECLS
+
+#ifdef __cplusplus
+
+#include <functional>
+#include <utility>
+
+#if 0
+#if !(__cplusplus >= 201103L)
+#error "HarfBuzz C++ helpers require C++11"
+#endif
+#endif
+
+namespace hb {
+
+
+template <typename T>
+struct vtable;
+
+template <typename T>
+struct shared_ptr
+{
+ using element_type = T;
+
+ using v = vtable<T>;
+
+ explicit shared_ptr (T *p = nullptr) : p (p) {}
+ shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
+ shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
+ shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
+ shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ ~shared_ptr () { v::destroy (p); p = nullptr; }
+
+ T* get() const { return p; }
+
+ void swap (shared_ptr &o) { std::swap (p, o.p); }
+ friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
+
+ operator T * () const { return p; }
+ T& operator * () const { return *get (); }
+ T* operator -> () const { return get (); }
+ operator bool () { return p; }
+ bool operator == (const shared_ptr &o) { return p == o.p; }
+ bool operator != (const shared_ptr &o) { return p != o.p; }
+
+ static T* get_empty() { return v::get_empty (); }
+ T* reference() { return v::reference (p); }
+ void destroy() { v::destroy (p); }
+ void set_user_data (hb_user_data_key_t *key,
+ void *value,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace) { v::set_user_data (p, key, value, destroy, replace); }
+ void * get_user_data (hb_user_data_key_t *key) { return v::get_user_data (p, key); }
+
+ private:
+ T *p;
+};
+
+template<typename T> struct is_shared_ptr : std::false_type {};
+template<typename T> struct is_shared_ptr<shared_ptr<T>> : std::true_type {};
+
+template <typename T>
+struct unique_ptr
+{
+ using element_type = T;
+
+ using v = vtable<T>;
+
+ explicit unique_ptr (T *p = nullptr) : p (p) {}
+ unique_ptr (const unique_ptr &o) = delete;
+ unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
+ unique_ptr& operator = (const unique_ptr &o) = delete;
+ unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ ~unique_ptr () { v::destroy (p); p = nullptr; }
+
+ T* get() const { return p; }
+ T* release () { T* v = p; p = nullptr; return v; }
+
+ void swap (unique_ptr &o) { std::swap (p, o.p); }
+ friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
+
+ operator T * () const { return p; }
+ T& operator * () const { return *get (); }
+ T* operator -> () const { return get (); }
+ operator bool () { return p; }
+
+ private:
+ T *p;
+};
+
+template<typename T> struct is_unique_ptr : std::false_type {};
+template<typename T> struct is_unique_ptr<unique_ptr<T>> : std::true_type {};
+
+template <typename T,
+ T * (*_get_empty) (void),
+ T * (*_reference) (T *),
+ void (*_destroy) (T *),
+ hb_bool_t (*_set_user_data) (T *,
+ hb_user_data_key_t *,
+ void *,
+ hb_destroy_func_t,
+ hb_bool_t),
+ void * (*_get_user_data) (T *,
+ hb_user_data_key_t *)>
+struct vtable_t
+{
+ static constexpr auto get_empty = _get_empty;
+ static constexpr auto reference = _reference;
+ static constexpr auto destroy = _destroy;
+ static constexpr auto set_user_data = _set_user_data;
+ static constexpr auto get_user_data = _get_user_data;
+};
+
+#define HB_DEFINE_VTABLE(name) \
+ template<> \
+ struct vtable<hb_##name##_t> \
+ : vtable_t<hb_##name##_t, \
+ &hb_##name##_get_empty, \
+ &hb_##name##_reference, \
+ &hb_##name##_destroy, \
+ &hb_##name##_set_user_data, \
+ &hb_##name##_get_user_data> {}
+
+HB_DEFINE_VTABLE (buffer);
+HB_DEFINE_VTABLE (blob);
+HB_DEFINE_VTABLE (face);
+HB_DEFINE_VTABLE (font);
+HB_DEFINE_VTABLE (font_funcs);
+HB_DEFINE_VTABLE (map);
+HB_DEFINE_VTABLE (set);
+HB_DEFINE_VTABLE (shape_plan);
+HB_DEFINE_VTABLE (unicode_funcs);
+
+#undef HB_DEFINE_VTABLE
+
+
+} // namespace hb
+
+template<typename T>
+struct std::hash<hb::shared_ptr<T>>
+{
+ std::size_t operator()(const hb::shared_ptr<T>& v) const noexcept
+ {
+ std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
+ return h;
+ }
+};
+
+template<typename T>
+struct std::hash<hb::unique_ptr<T>>
+{
+ std::size_t operator()(const hb::unique_ptr<T>& v) const noexcept
+ {
+ std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
+ return h;
+ }
+};
+
+
+#endif /* __cplusplus */
+
+#endif /* HB_CPLUSPLUS_HH */
diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc
index f177ff31c0..ce04f5bab1 100644
--- a/thirdparty/harfbuzz/src/hb-directwrite.cc
+++ b/thirdparty/harfbuzz/src/hb-directwrite.cc
@@ -241,17 +241,12 @@ struct hb_directwrite_font_data_t {};
hb_directwrite_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
- hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
- if (unlikely (!data))
- return nullptr;
-
- return data;
+ return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
{
- delete data;
}
diff --git a/thirdparty/harfbuzz/src/hb-draw.cc b/thirdparty/harfbuzz/src/hb-draw.cc
index b31019b07e..fdc71102d6 100644
--- a/thirdparty/harfbuzz/src/hb-draw.cc
+++ b/thirdparty/harfbuzz/src/hb-draw.cc
@@ -56,12 +56,14 @@ hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
+#define HB_ONE_THIRD 0.33333333f
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,
+ (st->current_x + 2.f * control_x) * HB_ONE_THIRD,
+ (st->current_y + 2.f * control_y) * HB_ONE_THIRD,
+ (to_x + 2.f * control_x) * HB_ONE_THIRD,
+ (to_y + 2.f * control_y) * HB_ONE_THIRD,
to_x, to_y);
+#undef HB_ONE_THIRD
}
static void
@@ -89,25 +91,46 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \
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; \
- } \
+ if (dfuncs->destroy && dfuncs->destroy->name) \
+ dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \
+ \
+ if (user_data && !dfuncs->user_data) \
+ { \
+ dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \
+ if (unlikely (!dfuncs->user_data)) \
+ goto fail; \
+ } \
+ if (destroy && !dfuncs->destroy) \
+ { \
+ dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \
+ if (unlikely (!dfuncs->destroy)) \
+ goto fail; \
+ } \
+ \
+ if (func) { \
+ dfuncs->func.name = func; \
+ if (dfuncs->user_data) \
+ dfuncs->user_data->name = user_data; \
+ if (dfuncs->destroy) \
+ dfuncs->destroy->name = destroy; \
+ } else { \
+ dfuncs->func.name = hb_draw_##name##_nil; \
+ if (dfuncs->user_data) \
+ dfuncs->user_data->name = nullptr; \
+ if (dfuncs->destroy) \
+ dfuncs->destroy->name = nullptr; \
+ } \
+ \
+fail: \
+ if (destroy) \
+ destroy (user_data); \
}
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
/**
- * hb_draw_funcs_create: (Xconstructor)
+ * hb_draw_funcs_create:
*
* Creates a new draw callbacks object.
*
@@ -177,11 +200,13 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
{
if (!hb_object_destroy (dfuncs)) return;
+ if (dfuncs->destroy)
+ {
#define HB_DRAW_FUNC_IMPLEMENT(name) \
- if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name);
- HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+ if (dfuncs->destroy->name) dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name);
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
-
+ }
hb_free (dfuncs);
}
diff --git a/thirdparty/harfbuzz/src/hb-draw.hh b/thirdparty/harfbuzz/src/hb-draw.hh
index 28bc9218e1..768f51a875 100644
--- a/thirdparty/harfbuzz/src/hb-draw.hh
+++ b/thirdparty/harfbuzz/src/hb-draw.hh
@@ -54,31 +54,31 @@ struct hb_draw_funcs_t
#define HB_DRAW_FUNC_IMPLEMENT(name) void *name;
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
- } user_data;
+ } *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;
+ } *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); }
+ !user_data ? nullptr : 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); }
+ !user_data ? nullptr : 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); }
+ !user_data ? nullptr : 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,
@@ -87,10 +87,10 @@ struct hb_draw_funcs_t
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y,
- user_data.cubic_to); }
+ !user_data ? nullptr : 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); }
+ !user_data ? nullptr : user_data->close_path); }
void move_to (void *draw_data, hb_draw_state_t &st,
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 5365598636..7cdd6cb49f 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -190,7 +190,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
}
/**
- * hb_face_create: (Xconstructor)
+ * hb_face_create:
* @blob: #hb_blob_t to work upon
* @index: The index of the face within @blob
*
@@ -342,7 +342,7 @@ hb_face_set_user_data (hb_face_t *face,
* Since: 0.9.2
**/
void *
-hb_face_get_user_data (const hb_face_t *face,
+hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (face, key);
diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h
index 6ef2f8b886..3b7477a76c 100644
--- a/thirdparty/harfbuzz/src/hb-face.h
+++ b/thirdparty/harfbuzz/src/hb-face.h
@@ -96,7 +96,7 @@ hb_face_set_user_data (hb_face_t *face,
hb_bool_t replace);
HB_EXTERN void *
-hb_face_get_user_data (const hb_face_t *face,
+hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key);
HB_EXTERN void
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index db05f017a5..8c4fe863b6 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -636,16 +636,8 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- },
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- },
+ nullptr,
+ nullptr,
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
@@ -658,16 +650,8 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
static const hb_font_funcs_t _hb_font_funcs_default = {
HB_OBJECT_HEADER_STATIC,
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- },
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- },
+ nullptr,
+ nullptr,
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default,
@@ -679,7 +663,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
/**
- * hb_font_funcs_create: (Xconstructor)
+ * hb_font_funcs_create:
*
* Creates a new #hb_font_funcs_t structure of font functions.
*
@@ -746,10 +730,16 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
{
if (!hb_object_destroy (ffuncs)) return;
-#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \
- ffuncs->destroy.name (ffuncs->user_data.name);
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+ if (ffuncs->destroy)
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \
+ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name);
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
+ }
+
+ hb_free (ffuncs->destroy);
+ hb_free (ffuncs->user_data);
hb_free (ffuncs);
}
@@ -841,24 +831,50 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
hb_destroy_func_t destroy) \
{ \
if (hb_object_is_immutable (ffuncs)) \
+ goto fail; \
+ \
+ if (!func) \
{ \
if (destroy) \
destroy (user_data); \
- return; \
+ destroy = nullptr; \
+ user_data = nullptr; \
} \
\
- if (ffuncs->destroy.name) \
- ffuncs->destroy.name (ffuncs->user_data.name); \
+ if (ffuncs->destroy && ffuncs->destroy->name) \
+ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \
+ \
+ if (user_data && !ffuncs->user_data) \
+ { \
+ ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \
+ if (unlikely (!ffuncs->user_data)) \
+ goto fail; \
+ } \
+ if (destroy && !ffuncs->destroy) \
+ { \
+ ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \
+ if (unlikely (!ffuncs->destroy)) \
+ goto fail; \
+ } \
\
if (func) { \
ffuncs->get.f.name = func; \
- ffuncs->user_data.name = user_data; \
- ffuncs->destroy.name = destroy; \
+ if (ffuncs->user_data) \
+ ffuncs->user_data->name = user_data; \
+ if (ffuncs->destroy) \
+ ffuncs->destroy->name = destroy; \
} else { \
ffuncs->get.f.name = hb_font_get_##name##_default; \
- ffuncs->user_data.name = nullptr; \
- ffuncs->destroy.name = nullptr; \
+ if (ffuncs->user_data) \
+ ffuncs->user_data->name = nullptr; \
+ if (ffuncs->destroy) \
+ ffuncs->destroy->name = nullptr; \
} \
+ return; \
+ \
+fail: \
+ if (destroy) \
+ destroy (user_data); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -1623,6 +1639,9 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
{
HB_OBJECT_HEADER_STATIC,
+ 0, /* serial */
+ 0, /* serial_coords */
+
nullptr, /* parent */
const_cast<hb_face_t *> (&_hb_Null_hb_face_t),
@@ -1630,6 +1649,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
1000, /* y_scale */
0., /* slant */
0., /* slant_xy; */
+ 1.f, /* x_multf */
+ 1.f, /* y_multf */
1<<16, /* x_mult */
1<<16, /* y_mult */
@@ -1662,14 +1683,15 @@ _hb_font_create (hb_face_t *face)
font->face = hb_face_reference (face);
font->klass = hb_font_funcs_get_empty ();
font->data.init0 (font);
- font->x_scale = font->y_scale = hb_face_get_upem (face);
+ font->x_scale = font->y_scale = face->get_upem ();
+ font->x_multf = font->y_multf = 1.f;
font->x_mult = font->y_mult = 1 << 16;
return font;
}
/**
- * hb_font_create: (Xconstructor)
+ * hb_font_create:
* @face: a face.
*
* Constructs a new font object from the specified face.
@@ -1715,6 +1737,8 @@ _hb_font_adopt_var_coords (hb_font_t *font,
font->coords = coords;
font->design_coords = design_coords;
font->num_coords = coords_length;
+
+ font->mults_changed (); // Easiest to call this to drop cached data
}
/**
@@ -1744,7 +1768,6 @@ 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;
font->ptem = parent->ptem;
@@ -1767,6 +1790,8 @@ hb_font_create_sub_font (hb_font_t *parent)
}
}
+ font->mults_changed ();
+
return font;
}
@@ -1852,6 +1877,9 @@ hb_font_set_user_data (hb_font_t *font,
hb_destroy_func_t destroy /* May be NULL. */,
hb_bool_t replace)
{
+ if (!hb_object_is_immutable (font))
+ font->serial++;
+
return hb_object_set_user_data (font, key, data, destroy, replace);
}
@@ -1911,6 +1939,45 @@ hb_font_is_immutable (hb_font_t *font)
}
/**
+ * hb_font_get_serial:
+ * @font: #hb_font_t to work upon
+ *
+ * Returns the internal serial number of the font. The serial
+ * number is increased every time a setting on the font is
+ * changed, using a setter function.
+ *
+ * Return value: serial number
+ *
+ * Since: 4.4.0.
+ **/
+unsigned int
+hb_font_get_serial (hb_font_t *font)
+{
+ return font->serial;
+}
+
+/**
+ * hb_font_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Notifies the @font that underlying font data has changed.
+ * This has the effect of increasing the serial as returned
+ * by hb_font_get_serial(), which invalidates internal caches.
+ *
+ * Since: 4.4.0.
+ **/
+void
+hb_font_changed (hb_font_t *font)
+{
+ if (hb_object_is_immutable (font))
+ return;
+
+ font->serial++;
+
+ font->mults_changed ();
+}
+
+/**
* hb_font_set_parent:
* @font: #hb_font_t to work upon
* @parent: The parent font object to assign
@@ -1926,6 +1993,11 @@ hb_font_set_parent (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ if (parent == font->parent)
+ return;
+
+ font->serial++;
+
if (!parent)
parent = hb_font_get_empty ();
@@ -1968,6 +2040,11 @@ hb_font_set_face (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ if (face == font->face)
+ return;
+
+ font->serial++;
+
if (unlikely (!face))
face = hb_face_get_empty ();
@@ -2022,6 +2099,8 @@ hb_font_set_funcs (hb_font_t *font,
return;
}
+ font->serial++;
+
if (font->destroy)
font->destroy (font->user_data);
@@ -2059,6 +2138,8 @@ hb_font_set_funcs_data (hb_font_t *font,
return;
}
+ font->serial++;
+
if (font->destroy)
font->destroy (font->user_data);
@@ -2085,6 +2166,11 @@ hb_font_set_scale (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ if (font->x_scale == x_scale && font->y_scale == y_scale)
+ return;
+
+ font->serial++;
+
font->x_scale = x_scale;
font->y_scale = y_scale;
font->mults_changed ();
@@ -2127,6 +2213,11 @@ hb_font_set_ppem (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
+ return;
+
+ font->serial++;
+
font->x_ppem = x_ppem;
font->y_ppem = y_ppem;
}
@@ -2169,6 +2260,11 @@ hb_font_set_ptem (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ if (font->ptem == ptem)
+ return;
+
+ font->serial++;
+
font->ptem = ptem;
}
@@ -2216,6 +2312,11 @@ hb_font_set_synthetic_slant (hb_font_t *font, float slant)
if (hb_object_is_immutable (font))
return;
+ if (font->slant == slant)
+ return;
+
+ font->serial++;
+
font->slant = slant;
font->mults_changed ();
}
@@ -2263,6 +2364,8 @@ hb_font_set_variations (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ font->serial_coords = ++font->serial;
+
if (!variations_length)
{
hb_font_set_var_coords_normalized (font, nullptr, 0);
@@ -2322,6 +2425,8 @@ hb_font_set_var_coords_design (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ font->serial_coords = ++font->serial;
+
int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
@@ -2355,6 +2460,8 @@ hb_font_set_var_named_instance (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ font->serial_coords = ++font->serial;
+
unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
@@ -2391,6 +2498,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
+ font->serial_coords = ++font->serial;
+
int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
@@ -2596,12 +2705,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 9548857535..ca6ecf7963 100644
--- a/thirdparty/harfbuzz/src/hb-font.h
+++ b/thirdparty/harfbuzz/src/hb-font.h
@@ -1002,6 +1002,12 @@ hb_font_make_immutable (hb_font_t *font);
HB_EXTERN hb_bool_t
hb_font_is_immutable (hb_font_t *font);
+HB_EXTERN unsigned int
+hb_font_get_serial (hb_font_t *font);
+
+HB_EXTERN void
+hb_font_changed (hb_font_t *font);
+
HB_EXTERN void
hb_font_set_parent (hb_font_t *font,
hb_font_t *parent);
diff --git a/thirdparty/harfbuzz/src/hb-font.hh b/thirdparty/harfbuzz/src/hb-font.hh
index 70311b4a85..bb402e23eb 100644
--- a/thirdparty/harfbuzz/src/hb-font.hh
+++ b/thirdparty/harfbuzz/src/hb-font.hh
@@ -68,13 +68,13 @@ struct hb_font_funcs_t
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
- } user_data;
+ } *user_data;
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
- } destroy;
+ } *destroy;
/* Don't access these directly. Call font->get_*() instead. */
union get_t {
@@ -104,6 +104,8 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
struct hb_font_t
{
hb_object_header_t header;
+ unsigned int serial;
+ unsigned int serial_coords;
hb_font_t *parent;
hb_face_t *face;
@@ -112,6 +114,8 @@ struct hb_font_t
int32_t y_scale;
float slant;
float slant_xy;
+ float x_multf;
+ float y_multf;
int64_t x_mult;
int64_t y_mult;
@@ -137,12 +141,12 @@ struct hb_font_t
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
- hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
- 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_scalef_x (float v) { return em_multf (v, x_multf); }
+ hb_position_t em_scalef_y (float v) { return em_multf (v, y_multf); }
+ float em_fscale_x (int16_t v) { return em_fmult (v, x_multf); }
+ float em_fscale_y (int16_t v) { return em_fmult (v, y_multf); }
+ float em_fscalef_x (float v) { return em_fmultf (v, x_multf); }
+ float em_fscalef_y (float v) { return em_fmultf (v, y_multf); }
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_mult (v, dir_mult (direction)); }
@@ -205,14 +209,14 @@ struct hb_font_t
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_h_extents (this, user_data,
extents,
- klass->user_data.font_h_extents);
+ !klass->user_data ? nullptr : klass->user_data->font_h_extents);
}
hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_v_extents (this, user_data,
extents,
- klass->user_data.font_v_extents);
+ !klass->user_data ? nullptr : klass->user_data->font_v_extents);
}
bool has_glyph (hb_codepoint_t unicode)
@@ -228,7 +232,7 @@ struct hb_font_t
*glyph = not_found;
return klass->get.f.nominal_glyph (this, user_data,
unicode, glyph,
- klass->user_data.nominal_glyph);
+ !klass->user_data ? nullptr : klass->user_data->nominal_glyph);
}
unsigned int get_nominal_glyphs (unsigned int count,
const hb_codepoint_t *first_unicode,
@@ -240,7 +244,7 @@ struct hb_font_t
count,
first_unicode, unicode_stride,
first_glyph, glyph_stride,
- klass->user_data.nominal_glyphs);
+ !klass->user_data ? nullptr : klass->user_data->nominal_glyphs);
}
hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@@ -250,21 +254,21 @@ struct hb_font_t
*glyph = not_found;
return klass->get.f.variation_glyph (this, user_data,
unicode, variation_selector, glyph,
- klass->user_data.variation_glyph);
+ !klass->user_data ? nullptr : klass->user_data->variation_glyph);
}
hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_h_advance (this, user_data,
glyph,
- klass->user_data.glyph_h_advance);
+ !klass->user_data ? nullptr : klass->user_data->glyph_h_advance);
}
hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_v_advance (this, user_data,
glyph,
- klass->user_data.glyph_v_advance);
+ !klass->user_data ? nullptr : klass->user_data->glyph_v_advance);
}
void get_glyph_h_advances (unsigned int count,
@@ -277,7 +281,7 @@ struct hb_font_t
count,
first_glyph, glyph_stride,
first_advance, advance_stride,
- klass->user_data.glyph_h_advances);
+ !klass->user_data ? nullptr : klass->user_data->glyph_h_advances);
}
void get_glyph_v_advances (unsigned int count,
@@ -290,7 +294,7 @@ struct hb_font_t
count,
first_glyph, glyph_stride,
first_advance, advance_stride,
- klass->user_data.glyph_v_advances);
+ !klass->user_data ? nullptr : klass->user_data->glyph_v_advances);
}
hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
@@ -299,7 +303,7 @@ struct hb_font_t
*x = *y = 0;
return klass->get.f.glyph_h_origin (this, user_data,
glyph, x, y,
- klass->user_data.glyph_h_origin);
+ !klass->user_data ? nullptr : klass->user_data->glyph_h_origin);
}
hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
@@ -308,7 +312,7 @@ struct hb_font_t
*x = *y = 0;
return klass->get.f.glyph_v_origin (this, user_data,
glyph, x, y,
- klass->user_data.glyph_v_origin);
+ !klass->user_data ? nullptr : klass->user_data->glyph_v_origin);
}
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
@@ -319,7 +323,7 @@ struct hb_font_t
#else
return klass->get.f.glyph_h_kerning (this, user_data,
left_glyph, right_glyph,
- klass->user_data.glyph_h_kerning);
+ !klass->user_data ? nullptr : klass->user_data->glyph_h_kerning);
#endif
}
@@ -331,7 +335,7 @@ struct hb_font_t
#else
return klass->get.f.glyph_v_kerning (this, user_data,
top_glyph, bottom_glyph,
- klass->user_data.glyph_v_kerning);
+ !klass->user_data ? nullptr : klass->user_data->glyph_v_kerning);
#endif
}
@@ -342,7 +346,7 @@ struct hb_font_t
return klass->get.f.glyph_extents (this, user_data,
glyph,
extents,
- klass->user_data.glyph_extents);
+ !klass->user_data ? nullptr : klass->user_data->glyph_extents);
}
hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
@@ -352,7 +356,7 @@ struct hb_font_t
return klass->get.f.glyph_contour_point (this, user_data,
glyph, point_index,
x, y,
- klass->user_data.glyph_contour_point);
+ !klass->user_data ? nullptr : klass->user_data->glyph_contour_point);
}
hb_bool_t get_glyph_name (hb_codepoint_t glyph,
@@ -362,7 +366,7 @@ struct hb_font_t
return klass->get.f.glyph_name (this, user_data,
glyph,
name, size,
- klass->user_data.glyph_name);
+ !klass->user_data ? nullptr : klass->user_data->glyph_name);
}
hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
@@ -373,7 +377,7 @@ struct hb_font_t
return klass->get.f.glyph_from_name (this, user_data,
name, len,
glyph,
- klass->user_data.glyph_from_name);
+ !klass->user_data ? nullptr : klass->user_data->glyph_from_name);
}
void get_glyph_shape (hb_codepoint_t glyph,
@@ -382,7 +386,7 @@ struct hb_font_t
klass->get.f.glyph_shape (this, user_data,
glyph,
draw_funcs, draw_data,
- klass->user_data.glyph_shape);
+ !klass->user_data ? nullptr : klass->user_data->glyph_shape);
}
@@ -444,7 +448,6 @@ struct hb_font_t
{
*x = get_glyph_h_advance (glyph) / 2;
- /* TODO cache this somehow?! */
hb_font_extents_t extents;
get_h_extents_with_fallback (&extents);
*y = extents.ascender;
@@ -628,20 +631,26 @@ struct hb_font_t
void mults_changed ()
{
- signed upem = face->get_upem ();
- x_mult = ((int64_t) x_scale << 16) / upem;
- y_mult = ((int64_t) y_scale << 16) / upem;
+ float upem = face->get_upem ();
+ x_multf = x_scale / upem;
+ y_multf = y_scale / upem;
+ bool x_neg = x_scale < 0;
+ x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem;
+ bool y_neg = y_scale < 0;
+ y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
+
+ data.fini ();
}
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 (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 (); }
+ hb_position_t em_multf (float v, float mult)
+ { return (hb_position_t) roundf (em_fmultf (v, mult)); }
+ float em_fmultf (float v, float mult)
+ { return v * mult; }
+ float em_fmult (int16_t v, float mult)
+ { return (float) v * mult; }
};
DECLARE_NULL_INSTANCE (hb_font_t);
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index 0cfbb22e31..b526a82865 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -37,6 +37,8 @@
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-cache.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-shaper-arabic-pua.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
@@ -80,13 +82,13 @@
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 int cached_x_scale;
+ mutable hb_mutex_t lock;
+ FT_Face ft_face;
+ mutable unsigned cached_serial;
mutable hb_advance_cache_t advance_cache;
};
@@ -103,7 +105,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
- ft_font->cached_x_scale = 0;
+ ft_font->cached_serial = (unsigned) -1;
ft_font->advance_cache.init ();
return ft_font;
@@ -130,6 +132,58 @@ _hb_ft_font_destroy (void *data)
hb_free (ft_font);
}
+
+/* hb_font changed, update FT_Face. */
+static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
+{
+
+ FT_Set_Char_Size (ft_face,
+ abs (font->x_scale), abs (font->y_scale),
+ 0, 0);
+#if 0
+ font->x_ppem * 72 * 64 / font->x_scale,
+ font->y_ppem * 72 * 64 / font->y_scale);
+#endif
+ if (font->x_scale < 0 || font->y_scale < 0)
+ {
+ FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
+ 0, font->y_scale < 0 ? -1 : +1};
+ FT_Set_Transform (ft_face, &matrix, nullptr);
+ }
+
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
+ unsigned int num_coords;
+ const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
+ if (num_coords)
+ {
+ FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
+ if (ft_coords)
+ {
+ for (unsigned int i = 0; i < num_coords; i++)
+ ft_coords[i] = coords[i] * 4;
+ FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
+ hb_free (ft_coords);
+ }
+ }
+#endif
+}
+
+/* Check if hb_font changed, update FT_Face. */
+static inline bool
+_hb_ft_hb_font_check_changed (hb_font_t *font,
+ const hb_ft_font_t *ft_font)
+{
+ if (font->serial != ft_font->cached_serial)
+ {
+ _hb_ft_hb_font_changed (font, ft_font->ft_face);
+ ft_font->advance_cache.clear ();
+ ft_font->cached_serial = font->serial;
+ return true;
+ }
+ return false;
+}
+
+
/**
* hb_ft_font_set_load_flags:
* @font: #hb_font_t to work upon
@@ -181,7 +235,7 @@ hb_ft_font_get_load_flags (hb_font_t *font)
}
/**
- * hb_ft_font_get_face:
+ * hb_ft_font_get_face: (skip)
* @font: #hb_font_t to work upon
*
* Fetches the FT_Face associated with the specified #hb_font_t
@@ -203,7 +257,7 @@ hb_ft_font_get_face (hb_font_t *font)
}
/**
- * hb_ft_font_lock_face:
+ * hb_ft_font_lock_face: (skip)
* @font: #hb_font_t to work upon
*
* Gets the FT_Face associated with @font, This face will be kept around until
@@ -246,7 +300,7 @@ hb_ft_font_unlock_face (hb_font_t *font)
static hb_bool_t
-hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+hb_ft_get_nominal_glyph (hb_font_t *font,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
@@ -258,14 +312,29 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
if (unlikely (!g))
{
- if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
+ if (unlikely (ft_font->symbol))
{
- /* For symbol-encoded OpenType fonts, we duplicate the
- * U+F000..F0FF range at U+0000..U+00FF. That's what
- * Windows seems to do, and that's hinted about at:
- * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
- * under "Non-Standard (Symbol) Fonts". */
- g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
+ switch ((unsigned) font->face->table.OS2->get_font_page ()) {
+ case OT::OS2::font_page_t::FONT_PAGE_NONE:
+ if (unicode <= 0x00FFu)
+ /* For symbol-encoded OpenType fonts, we duplicate the
+ * U+F000..F0FF range at U+0000..U+00FF. That's what
+ * Windows seems to do, and that's hinted about at:
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
+ * under "Non-Standard (Symbol) Fonts". */
+ g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
+ break;
+#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+ case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
+ g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode));
+ break;
+ case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
+ g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode));
+ break;
+#endif
+ default:
+ break;
+ }
if (!g)
return false;
}
@@ -337,12 +406,6 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
int load_flags = ft_font->load_flags;
int mult = font->x_scale < 0 ? -1 : +1;
- if (font->x_scale != ft_font->cached_x_scale)
- {
- ft_font->advance_cache.clear ();
- ft_font->cached_x_scale = font->x_scale;
- }
-
for (unsigned int i = 0; i < count; i++)
{
FT_Fixed v = 0;
@@ -426,6 +489,7 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font,
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_Vector kerningv;
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
@@ -556,6 +620,7 @@ hb_ft_get_font_h_extents (hb_font_t *font 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;
+
metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
@@ -619,6 +684,8 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
+ _hb_ft_hb_font_check_changed (font, ft_font);
+
if (unlikely (FT_Load_Glyph (ft_face, glyph,
FT_LOAD_NO_BITMAP | ft_font->load_flags)))
return;
@@ -964,6 +1031,31 @@ hb_ft_font_changed (hb_font_t *font)
}
/**
+ * hb_ft_hb_font_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
+ * @font has changed.
+ * This function should be called after changing the size or
+ * variation-axis settings on the @font.
+ * This call is fast if nothing has changed on @font.
+ *
+ * Return value: true if changed, false otherwise
+ *
+ * Since: 4.4.0
+ **/
+hb_bool_t
+hb_ft_hb_font_changed (hb_font_t *font)
+{
+ if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+ return false;
+
+ hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+ return _hb_ft_hb_font_check_changed (font, ft_font);
+}
+
+/**
* hb_ft_font_create_referenced:
* @ft_face: FT_Face to work upon
*
@@ -1081,35 +1173,7 @@ hb_ft_font_set_funcs (hb_font_t *font)
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
- FT_Set_Char_Size (ft_face,
- abs (font->x_scale), abs (font->y_scale),
- 0, 0);
-#if 0
- font->x_ppem * 72 * 64 / font->x_scale,
- font->y_ppem * 72 * 64 / font->y_scale);
-#endif
- if (font->x_scale < 0 || font->y_scale < 0)
- {
- FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
- 0, font->y_scale < 0 ? -1 : +1};
- FT_Set_Transform (ft_face, &matrix, nullptr);
- }
-
-#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
- unsigned int num_coords;
- const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
- if (num_coords)
- {
- FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
- if (ft_coords)
- {
- for (unsigned int i = 0; i < num_coords; i++)
- ft_coords[i] = coords[i] * 4;
- FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
- hb_free (ft_coords);
- }
- }
-#endif
+ _hb_ft_hb_font_changed (font, ft_face);
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
diff --git a/thirdparty/harfbuzz/src/hb-ft.h b/thirdparty/harfbuzz/src/hb-ft.h
index bf07115ab9..6a8a7abe8c 100644
--- a/thirdparty/harfbuzz/src/hb-ft.h
+++ b/thirdparty/harfbuzz/src/hb-ft.h
@@ -122,10 +122,17 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
HB_EXTERN int
hb_ft_font_get_load_flags (hb_font_t *font);
-/* Call when size or variations settings on underlying FT_Face change. */
+/* Call when size or variations settings on underlying FT_Face changed,
+ * and you want to update the hb_font_t from it. */
HB_EXTERN void
hb_ft_font_changed (hb_font_t *font);
+/* Call when size or variations settings on underlying hb_font_t may have
+ * changed, and you want to update the FT_Face from it. This call is fast
+ * if nothing changed on hb_font_t. Returns true if changed. */
+HB_EXTERN hb_bool_t
+hb_ft_hb_font_changed (hb_font_t *font);
+
/* Makes an hb_font_t use FreeType internally to implement font functions.
* Note: this internally creates an FT_Face. Use it when you create your
* hb_face_t using hb_face_create(). */
diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh
index 43a3098f65..d4461f166c 100644
--- a/thirdparty/harfbuzz/src/hb-iter.hh
+++ b/thirdparty/harfbuzz/src/hb-iter.hh
@@ -43,17 +43,12 @@
* is writable, then the iterator returns lvalues, otherwise it
* returns rvalues.
*
- * TODO Document more.
- *
- * If iterator implementation implements operator!=, then can be
+ * If iterator implementation implements operator!=, then it can be
* used in range-based for loop. That already happens if the iterator
* is random-access. Otherwise, the range-based for loop incurs
* one traversal to find end(), which can be avoided if written
* as a while-style for loop, or if iterator implements a faster
- * __end__() method.
- * TODO When opting in for C++17, address this by changing return
- * type of .end()?
- */
+ * __end__() method. */
/*
* Base classes for iterators.
@@ -75,10 +70,6 @@ struct hb_iter_t
iter_t* thiz () { return static_cast< iter_t *> (this); }
public:
- /* TODO:
- * Port operators below to use hb_enable_if to sniff which method implements
- * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
-
/* Operators. */
iter_t iter () const { return *thiz(); }
iter_t operator + () const { return *thiz(); }
@@ -87,8 +78,7 @@ struct hb_iter_t
explicit operator bool () const { return thiz()->__more__ (); }
unsigned len () const { return thiz()->__len__ (); }
/* The following can only be enabled if item_t is reference type. Otherwise
- * it will be returning pointer to temporary rvalue.
- * TODO Use a wrapper return type to fix for non-reference type. */
+ * it will be returning pointer to temporary rvalue. */
template <typename T = item_t,
hb_enable_if (std::is_reference<T>::value)>
hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); }
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index e52a6a4124..ff2a99f5ed 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -176,7 +176,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
void init () { instance.set_relaxed (nullptr); }
- void fini () { do_destroy (instance.get ()); }
+ void fini () { do_destroy (instance.get ()); init (); }
void free_instance ()
{
diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc
index 9f1ac42846..089615c72a 100644
--- a/thirdparty/harfbuzz/src/hb-map.cc
+++ b/thirdparty/harfbuzz/src/hb-map.cc
@@ -40,7 +40,7 @@
/**
- * hb_map_create: (Xconstructor)
+ * hb_map_create:
*
* Creates a new, initially empty map.
*
@@ -172,6 +172,25 @@ hb_map_allocation_successful (const hb_map_t *map)
return map->successful;
}
+/**
+ * hb_map_copy:
+ * @map: A map
+ *
+ * Allocate a copy of @map.
+ *
+ * Return value: Newly-allocated map.
+ *
+ * Since: 4.4.0
+ **/
+hb_map_t *
+hb_map_copy (const hb_map_t *map)
+{
+ hb_map_t *copy = hb_map_create ();
+ if (unlikely (!copy)) return nullptr;
+ copy->resize (map->population);
+ hb_copy (*map, *copy);
+ return copy;
+}
/**
* hb_map_set:
@@ -289,3 +308,40 @@ 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);
+}
+
+/**
+ * hb_map_hash:
+ * @map: A map
+ *
+ * Creates a hash representing @map.
+ *
+ * Return value:
+ * A hash of @map.
+ *
+ * Since: 4.4.0
+ **/
+HB_EXTERN unsigned int
+hb_map_hash (const hb_map_t *map)
+{
+ return map->hash ();
+}
+
diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h
index 6a45a7bdd5..41d877d6a1 100644
--- a/thirdparty/harfbuzz/src/hb-map.h
+++ b/thirdparty/harfbuzz/src/hb-map.h
@@ -82,6 +82,9 @@ hb_map_get_user_data (hb_map_t *map,
HB_EXTERN hb_bool_t
hb_map_allocation_successful (const hb_map_t *map);
+HB_EXTERN hb_map_t *
+hb_map_copy (const hb_map_t *map);
+
HB_EXTERN void
hb_map_clear (hb_map_t *map);
@@ -91,6 +94,13 @@ 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 unsigned int
+hb_map_hash (const hb_map_t *map);
+
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 9341637eac..5efad8d20c 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -34,19 +34,18 @@
* hb_hashmap_t
*/
+extern HB_INTERNAL const hb_codepoint_t minus_1;
+
template <typename K, typename V,
- typename k_invalid_t = K,
- typename v_invalid_t = V,
- 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>
+ bool minus_one = false>
struct hb_hashmap_t
{
hb_hashmap_t () { init (); }
~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 ()
@@ -58,44 +57,53 @@ 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);
}
struct item_t
{
K key;
+ uint32_t hash : 30;
+ uint32_t is_used_ : 1;
+ uint32_t is_tombstone_ : 1;
V value;
- uint32_t hash;
+
+ bool is_used () const { return is_used_; }
+ void set_used (bool is_used) { is_used_ = is_used; }
+ bool is_tombstone () const { return is_tombstone_; }
+ void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; }
+ bool is_real () const { return is_used_ && !is_tombstone_; }
+
+ template <bool v = minus_one,
+ hb_enable_if (v == false)>
+ static inline const V& default_value () { return Null(V); };
+ template <bool v = minus_one,
+ hb_enable_if (v == true)>
+ static inline const V& default_value ()
+ {
+ static_assert (hb_is_same (V, hb_codepoint_t), "");
+ return minus_1;
+ };
void clear ()
{
new (std::addressof (key)) K ();
- key = hb_coerce<K> (kINVALID);
new (std::addressof (value)) V ();
- value = hb_coerce<V> (vINVALID);
hash = 0;
+ is_used_ = false;
+ is_tombstone_ = false;
}
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
- {
- 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); }
+ hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); }
+
+ uint32_t total_hash () const
+ { return (hash * 31) + hb_hash (value); }
};
hb_object_header_t header;
@@ -154,11 +162,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))
@@ -196,27 +204,39 @@ struct hb_hashmap_t
return true;
}
- bool set (K key, const V& value) { return set_with_hash (key, hb_hash (key), value); }
- bool set (K key, V&& value) { return set_with_hash (key, hb_hash (key), std::move (value)); }
+ template <typename VV>
+ bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
- V get (K key) const
+ const V& get (K key) const
{
- if (unlikely (!items)) return hb_coerce<V> (vINVALID);
+ if (unlikely (!items)) return item_t::default_value ();
unsigned int i = bucket_for (key);
- return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID);
+ return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value ();
}
- void del (K key) { set (key, hb_coerce<V> (vINVALID)); }
+ void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
/* Has interface. */
- typedef V value_t;
+ typedef const V& value_t;
value_t operator [] (K k) const { return get (k); }
- bool has (K k, V *vp = nullptr) const
+ bool has (K key, const V **vp = nullptr) const
{
- V v = (*this)[k];
- if (vp) *vp = v;
- const V vinv = hb_coerce<V> (vINVALID);
- return v != vinv;
+ if (unlikely (!items))
+ {
+ if (vp) *vp = &item_t::default_value ();
+ return false;
+ }
+ unsigned int i = bucket_for (key);
+ if (items[i].is_real () && items[i] == key)
+ {
+ if (vp) *vp = &items[i].value;
+ return true;
+ }
+ else
+ {
+ if (vp) *vp = &item_t::default_value ();
+ return false;
+ }
}
/* Projection. */
V operator () (K k) const { return get (k); }
@@ -235,6 +255,28 @@ 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 (const auto &item : + hb_array (items, mask ? mask + 1 : 0)
+ | hb_filter (&item_t::is_real))
+ h ^= item.total_hash ();
+ 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; }
/*
@@ -246,6 +288,12 @@ struct hb_hashmap_t
| hb_filter (&item_t::is_real)
| hb_map (&item_t::get_pair)
)
+ auto iter_ref () const HB_AUTO_RETURN
+ (
+ + hb_array (items, mask ? mask + 1 : 0)
+ | hb_filter (&item_t::is_real)
+ | hb_map (&item_t::get_pair_ref)
+ )
auto keys () const HB_AUTO_RETURN
(
+ hb_array (items, mask ? mask + 1 : 0)
@@ -268,19 +316,16 @@ struct hb_hashmap_t
protected:
template <typename VV>
- bool set_with_hash (K key, uint32_t hash, VV&& value)
+ bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false)
{
if (unlikely (!successful)) return false;
- 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);
- const V vinv = hb_coerce<V> (vINVALID);
- if (value == vinv && items[i].key != key)
+ if (is_delete && items[i].key != key)
return true; /* Trying to delete non-existent key. */
- if (!items[i].is_unused ())
+ if (items[i].is_used ())
{
occupancy--;
if (!items[i].is_tombstone ())
@@ -288,27 +333,30 @@ struct hb_hashmap_t
}
items[i].key = key;
- items[i].value = value;
+ items[i].value = std::forward<VV> (value);
items[i].hash = hash;
+ items[i].set_used (true);
+ items[i].set_tombstone (is_delete);
occupancy++;
- if (!items[i].is_tombstone ())
+ if (!is_delete)
population++;
return true;
}
- unsigned int bucket_for (K key) const
+ unsigned int bucket_for (const K &key) const
{
return bucket_for_hash (key, hb_hash (key));
}
- unsigned int bucket_for_hash (K key, uint32_t hash) const
+ unsigned int bucket_for_hash (const K &key, uint32_t hash) const
{
+ hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
unsigned int i = hash % prime;
unsigned int step = 0;
unsigned int tombstone = (unsigned) -1;
- while (!items[i].is_unused ())
+ while (items[i].is_used ())
{
if (items[i].hash == hash && items[i] == key)
return i;
@@ -377,21 +425,16 @@ struct hb_hashmap_t
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
hb_codepoint_t,
- hb_codepoint_t,
- hb_codepoint_t,
- HB_MAP_VALUE_INVALID,
- HB_MAP_VALUE_INVALID>
+ true>
{
using hashmap = hb_hashmap_t<hb_codepoint_t,
hb_codepoint_t,
- hb_codepoint_t,
- hb_codepoint_t,
- HB_MAP_VALUE_INVALID,
- HB_MAP_VALUE_INVALID>;
+ true>;
- hb_map_t () = default;
~hb_map_t () = default;
- hb_map_t (hb_map_t&) = default;
+ hb_map_t () : hashmap () {}
+ 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 3fea5d995e..e97d790fc3 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -188,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 defined(__GNUC__) && __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-null.hh b/thirdparty/harfbuzz/src/hb-null.hh
index db38a4dfd2..78eb6474d5 100644
--- a/thirdparty/harfbuzz/src/hb-null.hh
+++ b/thirdparty/harfbuzz/src/hb-null.hh
@@ -37,7 +37,7 @@
/* Global nul-content Null pool. Enlarge as necessary. */
-#define HB_NULL_POOL_SIZE 384
+#define HB_NULL_POOL_SIZE 448
/* Use SFINAE to sniff whether T has min_size; in which case return the larger
* of sizeof(T) and T::null_size, otherwise return sizeof(T).
@@ -108,7 +108,7 @@ struct NullHelper
/* Specializations for arbitrary-content Null objects expressed in bytes. */
#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
} /* Close namespace. */ \
- extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
+ extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]; \
template <> \
struct Null<Namespace::Type> { \
static Namespace::Type const & get_null () { \
@@ -118,7 +118,7 @@ struct NullHelper
namespace Namespace { \
static_assert (true, "") /* Require semicolon after. */
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
- const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
+ const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]
/* Specializations for arbitrary-content Null objects expressed as struct initializer. */
#define DECLARE_NULL_INSTANCE(Type) \
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 c102c15173..ae3b83a256 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -46,49 +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>
-{
- 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
{
@@ -100,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);
}
@@ -160,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;
@@ -172,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);
}
@@ -196,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);
}
@@ -209,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 */
@@ -233,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--)
@@ -243,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++;
@@ -256,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 df4554ac00..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;
@@ -541,10 +538,10 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
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);
+ 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;
@@ -566,18 +563,13 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
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>
@@ -598,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 542e3f4de3..4aa337f78b 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,38 @@ 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;
+ if (gid >= num_glyphs)
+ return;
+ 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 +546,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 +637,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 +1061,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 +1134,21 @@ 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; }
+ if (unlikely (fontDicts.in_error ())) { 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 +1163,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; }
@@ -1194,6 +1231,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))
@@ -1274,30 +1324,20 @@ struct cff1
{
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 ();
}
~accelerator_t ()
{
- glyph_names.fini ();
+ hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed ();
+ if (names)
+ {
+ names->fini ();
+ hb_free (names);
+ }
SUPER::fini ();
}
@@ -1305,9 +1345,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;
@@ -1319,7 +1359,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;
}
@@ -1333,11 +1373,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> *) hb_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 ();
+ hb_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 = names ? names->bsearch (key) : nullptr;
if (!gname) return false;
hb_codepoint_t gid = sid_to_glyph (gname->sid);
if (!gid && gname->sid) return false;
@@ -1359,7 +1441,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;
@@ -1368,7 +1450,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;
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
index 817fe064ce..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)
@@ -169,28 +167,28 @@ struct cff2_path_param_t
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, hb_draw_session_t &draw_session) const
{
@@ -202,9 +200,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
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);
+ 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;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
index b77e7f53fa..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
@@ -415,10 +411,10 @@ struct cff2
goto fail;
{ /* parse top dict */
- byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
+ hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
- cff2_top_dict_interpreter_t top_interp;
- top_interp.env.init (topDictStr);
+ num_interp_env_t env (topDictStr);
+ cff2_top_dict_interpreter_t top_interp (env);
topDict.init ();
if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
@@ -447,20 +443,20 @@ struct cff2
/* parse font dicts and gather private dicts */
for (unsigned int i = 0; i < fdCount; i++)
{
- const byte_str_t fontDictStr = (*fdArray)[i];
+ 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))) goto fail;
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
- const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp;
- priv_interp.env.init(privDictStr);
+ 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]))) goto fail;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index a8747ee5a1..09c9fe93f3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -27,6 +27,8 @@
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-shaper-arabic-pua.hh"
#include "hb-open-type.hh"
#include "hb-set.hh"
@@ -44,7 +46,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 +111,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 +288,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 +328,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;
@@ -401,7 +415,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;
@@ -421,7 +435,7 @@ struct CmapSubtableFormat4
gid += this->idDelta[i];
}
gid &= 0xFFFFu;
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -440,14 +454,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
@@ -456,11 +470,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);
}
}
}
@@ -469,6 +485,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. */
@@ -620,7 +638,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;
@@ -674,7 +692,7 @@ struct CmapSubtableTrimmed
};
struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
template <typename T>
struct CmapSubtableLongSegmented
@@ -684,7 +702,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;
@@ -722,11 +740,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)
{
@@ -778,16 +804,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;
@@ -818,7 +844,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)
@@ -1448,6 +1474,51 @@ struct EncodingRecord
DEFINE_SIZE_STATIC (8);
};
+struct SubtableUnicodesCache {
+
+ private:
+ const void* base;
+ hb_hashmap_t<intptr_t, hb::unique_ptr<hb_set_t>> cached_unicodes;
+
+ public:
+ SubtableUnicodesCache(const void* cmap_base)
+ : base(cmap_base), cached_unicodes() {}
+
+ hb_set_t* set_for (const EncodingRecord* record)
+ {
+ if (!cached_unicodes.has ((intptr_t) record))
+ {
+ hb_set_t *s = hb_set_create ();
+ if (unlikely (s->in_error ()))
+ return hb_set_get_empty ();
+
+ (base+record->subtable).collect_unicodes (s);
+
+ if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr<hb_set_t> {s})))
+ return hb_set_get_empty ();
+
+ return s;
+ }
+ return cached_unicodes.get ((intptr_t) record);
+ }
+
+};
+
+static inline uint_fast16_t
+_hb_symbol_pua_map (unsigned codepoint)
+{
+ if (codepoint <= 0x00FFu)
+ {
+ /* For symbol-encoded OpenType fonts, we duplicate the
+ * U+F000..F0FF range at U+0000..U+00FF. That's what
+ * Windows seems to do, and that's hinted about at:
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
+ * under "Non-Standard (Symbol) Fonts". */
+ return 0xF000u + codepoint;
+ }
+ return 0;
+}
+
struct cmap
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
@@ -1467,6 +1538,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 ())
@@ -1475,12 +1547,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.
@@ -1495,8 +1566,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);
}
@@ -1514,6 +1585,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)
{
@@ -1544,11 +1616,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;
@@ -1616,13 +1687,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); })
;
@@ -1677,7 +1742,24 @@ struct cmap
this->get_glyph_data = subtable;
if (unlikely (symbol))
- this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
+ {
+ switch ((unsigned) face->table.OS2->get_font_page ()) {
+ case OS2::font_page_t::FONT_PAGE_NONE:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
+ break;
+#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+ case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
+ break;
+ case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
+ break;
+#endif
+ default:
+ this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
+ break;
+ }
+ }
else
{
switch (subtable->u.format) {
@@ -1759,6 +1841,7 @@ struct cmap
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
+ typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
template <typename Type>
HB_INTERNAL static bool get_glyph_from (const void *obj,
@@ -1769,7 +1852,7 @@ struct cmap
return typed_obj->get_glyph (codepoint, glyph);
}
- template <typename Type>
+ template <typename Type, hb_pua_remap_func_t remap>
HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
@@ -1778,15 +1861,8 @@ struct cmap
if (likely (typed_obj->get_glyph (codepoint, glyph)))
return true;
- if (codepoint <= 0x00FFu)
- {
- /* For symbol-encoded OpenType fonts, we duplicate the
- * U+F000..F0FF range at U+0000..U+00FF. That's what
- * Windows seems to do, and that's hinted about at:
- * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
- * under "Non-Standard (Symbol) Fonts". */
- return typed_obj->get_glyph (0xF000u + codepoint, glyph);
- }
+ if (hb_codepoint_t c = remap (codepoint))
+ return typed_obj->get_glyph (c, glyph);
return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh
index a9deeba9a7..bcab77f79d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh
@@ -97,9 +97,10 @@ struct CPALV1Tail
c->push ();
for (const auto _ : colorLabels)
{
- if (!color_index_map->has (_)) continue;
+ const hb_codepoint_t *v;
+ if (!color_index_map->has (_, &v)) continue;
NameID new_color_idx;
- new_color_idx = color_index_map->get (_);
+ new_color_idx = *v;
if (!c->copy<NameID> (new_color_idx))
{
c->pop_discard ();
@@ -197,30 +198,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 +237,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 +253,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 9741ebd450..d0e2235fb2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh
@@ -298,6 +298,12 @@ struct sbix
const PNGHeader &png = *blob->as<PNGHeader>();
+ if (png.IHDR.height >= 65536 || png.IHDR.width >= 65536)
+ {
+ hb_blob_destroy (blob);
+ return false;
+ }
+
extents->x_bearing = x_offset;
extents->y_bearing = png.IHDR.height + y_offset;
extents->width = png.IHDR.width;
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc
index 0f44ee4d5f..af1bc86d48 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-font.cc
@@ -30,6 +30,7 @@
#include "hb-ot.h"
+#include "hb-cache.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-ot-face.hh"
@@ -58,6 +59,41 @@
* never need to call these functions directly.
**/
+struct hb_ot_font_t
+{
+ const hb_ot_face_t *ot_face;
+
+ /* h_advance caching */
+ mutable hb_atomic_int_t cached_coords_serial;
+ mutable hb_atomic_ptr_t<hb_advance_cache_t> advance_cache;
+};
+
+static hb_ot_font_t *
+_hb_ot_font_create (hb_font_t *font)
+{
+ hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t));
+ if (unlikely (!ot_font))
+ return nullptr;
+
+ ot_font->ot_face = &font->face->table;
+
+ return ot_font;
+}
+
+static void
+_hb_ot_font_destroy (void *font_data)
+{
+ hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data;
+
+ auto *cache = ot_font->advance_cache.get_relaxed ();
+ if (cache)
+ {
+ cache->fini ();
+ hb_free (cache);
+ }
+
+ hb_free (ot_font);
+}
static hb_bool_t
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
@@ -66,7 +102,8 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
return ot_face->cmap->get_nominal_glyph (unicode, glyph);
}
@@ -80,7 +117,8 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
return ot_face->cmap->get_nominal_glyphs (count,
first_unicode, unicode_stride,
first_glyph, glyph_stride);
@@ -94,7 +132,8 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph);
}
@@ -107,15 +146,83 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
- for (unsigned int i = 0; i < count; i++)
+#ifndef HB_NO_VAR
+ const OT::HVARVVAR &HVAR = *hmtx.var_table;
+ const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
+ OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+
+ bool use_cache = font->num_coords;
+#else
+ OT::VariationStore::cache_t *varStore_cache = nullptr;
+ bool use_cache = false;
+#endif
+
+ hb_advance_cache_t *cache = nullptr;
+ if (use_cache)
{
- *first_advance = font->em_scale_x (hmtx.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);
+ retry:
+ cache = ot_font->advance_cache.get ();
+ if (unlikely (!cache))
+ {
+ cache = (hb_advance_cache_t *) hb_malloc (sizeof (hb_advance_cache_t));
+ if (unlikely (!cache))
+ {
+ use_cache = false;
+ goto out;
+ }
+
+ cache->init ();
+ if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
+ {
+ hb_free (cache);
+ goto retry;
+ }
+ ot_font->cached_coords_serial.set (font->serial_coords);
+ }
+ }
+ out:
+
+ if (!use_cache)
+ {
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, varStore_cache));
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+ }
}
+ else
+ { /* Use cache. */
+ if (ot_font->cached_coords_serial.get () != (int) font->serial_coords)
+ {
+ ot_font->advance_cache->init ();
+ ot_font->cached_coords_serial.set (font->serial_coords);
+ }
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_position_t v;
+ unsigned cv;
+ if (ot_font->advance_cache->get (*first_glyph, &cv))
+ v = cv;
+ else
+ {
+ v = hmtx.get_advance (*first_glyph, font, varStore_cache);
+ ot_font->advance_cache->set (*first_glyph, v);
+ }
+ *first_advance = font->em_scale_x (v);
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+ }
+ }
+
+#ifndef HB_NO_VAR
+ OT::VariationStore::destroy_cache (varStore_cache);
+#endif
}
#ifndef HB_NO_VERTICAL
@@ -128,16 +235,31 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
if (vmtx.has_data ())
+ {
+#ifndef HB_NO_VAR
+ const OT::HVARVVAR &VVAR = *vmtx.var_table;
+ const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
+ OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
+#else
+ OT::VariationStore::cache_t *varStore_cache = nullptr;
+#endif
+
for (unsigned int i = 0; i < count; i++)
{
- *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
+ *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, varStore_cache));
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
+
+#ifndef HB_NO_VAR
+ OT::VariationStore::destroy_cache (varStore_cache);
+#endif
+ }
else
{
hb_font_extents_t font_extents;
@@ -163,7 +285,8 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
hb_position_t *y,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
*x = font->get_glyph_h_advance (glyph) / 2;
@@ -208,7 +331,8 @@ hb_ot_get_glyph_extents (hb_font_t *font,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
@@ -234,7 +358,9 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
+
if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
@@ -248,7 +374,9 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
- const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ const hb_ot_face_t *ot_face = ot_font->ot_face;
+
if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
@@ -364,10 +492,14 @@ _hb_ot_get_font_funcs ()
void
hb_ot_font_set_funcs (hb_font_t *font)
{
+ hb_ot_font_t *ot_font = _hb_ot_font_create (font);
+ if (unlikely (!ot_font))
+ return;
+
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
- &font->face->table,
- nullptr);
+ ot_font,
+ _hb_ot_font_destroy);
}
#ifndef HB_NO_VAR
diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
index b4ac688344..c32ff7636d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
@@ -30,1332 +30,6 @@
#ifndef HB_OT_GLYF_TABLE_HH
#define HB_OT_GLYF_TABLE_HH
-#include "hb-open-type.hh"
-#include "hb-ot-head-table.hh"
-#include "hb-ot-hmtx-table.hh"
-#include "hb-ot-var-gvar-table.hh"
-#include "hb-draw.hh"
-
-namespace OT {
-
-
-/*
- * loca -- Index to Location
- * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
- */
-#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
-
-#ifndef HB_MAX_COMPOSITE_OPERATIONS
-#define HB_MAX_COMPOSITE_OPERATIONS 100000
-#endif
-
-
-struct loca
-{
- friend struct glyf;
-
- static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
-
- bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
- {
- TRACE_SANITIZE (this);
- return_trace (true);
- }
-
- protected:
- UnsizedArrayOf<HBUINT8>
- dataZ; /* Location data. */
- public:
- DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
- * check the size externally, allow Null() object of it by
- * defining it _MIN instead. */
-};
-
-
-/*
- * glyf -- TrueType Glyph Data
- * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
- */
-#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
-
-
-struct glyf
-{
- static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
-
- bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
- {
- TRACE_SANITIZE (this);
- /* Runtime checks as eager sanitizing each glyph is costy */
- return_trace (true);
- }
-
- template<typename Iterator,
- hb_requires (hb_is_source_of (Iterator, unsigned int))>
- static bool
- _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
- {
- unsigned num_offsets = padded_offsets.len () + 1;
- unsigned entry_size = use_short_loca ? 2 : 4;
- char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
-
- if (unlikely (!loca_prime_data)) return false;
-
- DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
- entry_size, num_offsets, entry_size * num_offsets);
-
- if (use_short_loca)
- _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
- else
- _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
-
- hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
- entry_size * num_offsets,
- HB_MEMORY_MODE_WRITABLE,
- loca_prime_data,
- hb_free);
-
- bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
- && _add_head_and_set_loca_version (plan, use_short_loca);
-
- hb_blob_destroy (loca_blob);
- return result;
- }
-
- template<typename IteratorIn, typename IteratorOut,
- hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
- hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
- static void
- _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
- {
- unsigned int offset = 0;
- dest << 0;
- + it
- | hb_map ([=, &offset] (unsigned int padded_size)
- {
- offset += padded_size;
- DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
- return offset >> right_shift;
- })
- | hb_sink (dest)
- ;
- }
-
- /* requires source of SubsetGlyph complains the identifier isn't declared */
- template <typename Iterator>
- bool serialize (hb_serialize_context_t *c,
- Iterator it,
- bool use_short_loca,
- const hb_subset_plan_t *plan)
- {
- TRACE_SERIALIZE (this);
- unsigned init_len = c->length ();
- for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
-
- /* As a special case when all glyph in the font are empty, add a zero byte
- * to the table, so that OTS doesn’t reject it, and to make the table work
- * on Windows as well.
- * See https://github.com/khaledhosny/ots/issues/52 */
- if (init_len == c->length ())
- {
- HBUINT8 empty_byte;
- empty_byte = 0;
- c->copy (empty_byte);
- }
- return_trace (true);
- }
-
- /* Byte region(s) per glyph to output
- unpadded, hints removed if so requested
- If we fail to process a glyph we produce an empty (0-length) glyph */
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
-
- glyf *glyf_prime = c->serializer->start_embed <glyf> ();
- if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
-
- hb_vector_t<SubsetGlyph> glyphs;
- _populate_subset_glyphs (c->plan, &glyphs);
-
- auto padded_offsets =
- + hb_iter (glyphs)
- | hb_map (&SubsetGlyph::padded_size)
- ;
-
- unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
- bool use_short_loca = max_offset < 0x1FFFF;
-
-
- glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
- if (!use_short_loca) {
- padded_offsets =
- + hb_iter (glyphs)
- | hb_map (&SubsetGlyph::length)
- ;
- }
-
-
- if (unlikely (c->serializer->in_error ())) return_trace (false);
- return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
- padded_offsets,
- use_short_loca)));
- }
-
- template <typename SubsetGlyph>
- void
- _populate_subset_glyphs (const hb_subset_plan_t *plan,
- hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const
- {
- OT::glyf::accelerator_t glyf (plan->source);
-
- + hb_range (plan->num_output_glyphs ())
- | hb_map ([&] (hb_codepoint_t new_gid)
- {
- SubsetGlyph subset_glyph = {0};
- subset_glyph.new_gid = new_gid;
-
- /* should never fail: all old gids should be mapped */
- if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
- return subset_glyph;
-
- if (new_gid == 0 &&
- !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
- subset_glyph.source_glyph = Glyph ();
- else
- subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
- if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- subset_glyph.drop_hints_bytes ();
- else
- subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
- return subset_glyph;
- })
- | hb_sink (glyphs)
- ;
- }
-
- static bool
- _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
- {
- hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source);
- hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
- hb_blob_destroy (head_blob);
-
- if (unlikely (!head_prime_blob))
- return false;
-
- head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
- head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
- bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
-
- hb_blob_destroy (head_prime_blob);
- return success;
- }
-
- struct CompositeGlyphChain
- {
- protected:
- enum composite_glyph_flag_t
- {
- ARG_1_AND_2_ARE_WORDS = 0x0001,
- ARGS_ARE_XY_VALUES = 0x0002,
- ROUND_XY_TO_GRID = 0x0004,
- WE_HAVE_A_SCALE = 0x0008,
- MORE_COMPONENTS = 0x0020,
- WE_HAVE_AN_X_AND_Y_SCALE = 0x0040,
- WE_HAVE_A_TWO_BY_TWO = 0x0080,
- WE_HAVE_INSTRUCTIONS = 0x0100,
- USE_MY_METRICS = 0x0200,
- OVERLAP_COMPOUND = 0x0400,
- SCALED_COMPONENT_OFFSET = 0x0800,
- UNSCALED_COMPONENT_OFFSET = 0x1000
- };
-
- public:
- unsigned int get_size () const
- {
- unsigned int size = min_size;
- /* arg1 and 2 are int16 */
- if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
- /* arg1 and 2 are int8 */
- else size += 2;
-
- /* One x 16 bit (scale) */
- if (flags & WE_HAVE_A_SCALE) size += 2;
- /* Two x 16 bit (xscale, yscale) */
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
- /* Four x 16 bit (xscale, scale01, scale10, yscale) */
- else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
-
- return size;
- }
-
- void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; }
- hb_codepoint_t get_glyph_index () const { return glyphIndex; }
-
- void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
- void set_overlaps_flag ()
- {
- flags = (uint16_t) flags | OVERLAP_COMPOUND;
- }
-
- bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; }
-
- bool has_more () const { return flags & MORE_COMPONENTS; }
- bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
- bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); }
- void get_anchor_points (unsigned int &point1, unsigned int &point2) const
- {
- const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
- if (flags & ARG_1_AND_2_ARE_WORDS)
- {
- point1 = ((const HBUINT16 *) p)[0];
- point2 = ((const HBUINT16 *) p)[1];
- }
- else
- {
- point1 = p[0];
- point2 = p[1];
- }
- }
-
- void transform_points (contour_point_vector_t &points) const
- {
- float matrix[4];
- contour_point_t trans;
- if (get_transformation (matrix, trans))
- {
- if (scaled_offsets ())
- {
- points.translate (trans);
- points.transform (matrix);
- }
- else
- {
- points.transform (matrix);
- points.translate (trans);
- }
- }
- }
-
- protected:
- bool scaled_offsets () const
- { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
-
- bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
- {
- matrix[0] = matrix[3] = 1.f;
- matrix[1] = matrix[2] = 0.f;
-
- int tx, ty;
- const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
- if (flags & ARG_1_AND_2_ARE_WORDS)
- {
- tx = *(const HBINT16 *) p;
- p += HBINT16::static_size;
- ty = *(const HBINT16 *) p;
- p += HBINT16::static_size;
- }
- else
- {
- tx = *p++;
- ty = *p++;
- }
- if (is_anchored ()) tx = ty = 0;
-
- trans.init ((float) tx, (float) ty);
-
- {
- const F2DOT14 *points = (const F2DOT14 *) p;
- if (flags & WE_HAVE_A_SCALE)
- {
- matrix[0] = matrix[3] = points[0].to_float ();
- return true;
- }
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
- {
- matrix[0] = points[0].to_float ();
- matrix[3] = points[1].to_float ();
- return true;
- }
- else if (flags & WE_HAVE_A_TWO_BY_TWO)
- {
- matrix[0] = points[0].to_float ();
- matrix[1] = points[1].to_float ();
- matrix[2] = points[2].to_float ();
- matrix[3] = points[3].to_float ();
- return true;
- }
- }
- return tx || ty;
- }
-
- protected:
- HBUINT16 flags;
- HBGlyphID16 glyphIndex;
- public:
- DEFINE_SIZE_MIN (4);
- };
-
- struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &>
- {
- typedef const CompositeGlyphChain *__item_t__;
- composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
- glyph (glyph_), current (nullptr), current_size (0)
- {
- set_next (current_);
- }
-
- composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
-
- const CompositeGlyphChain &__item__ () const { return *current; }
- bool __more__ () const { return current; }
- void __next__ ()
- {
- if (!current->has_more ()) { current = nullptr; return; }
-
- set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
- }
- bool operator != (const composite_iter_t& o) const
- { return glyph != o.glyph || current != o.current; }
-
-
- void set_next (const CompositeGlyphChain *composite)
- {
- if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
- {
- current = nullptr;
- current_size = 0;
- return;
- }
- unsigned size = composite->get_size ();
- if (!glyph.check_range (composite, size))
- {
- current = nullptr;
- current_size = 0;
- return;
- }
-
- current = composite;
- current_size = size;
- }
-
- private:
- hb_bytes_t glyph;
- __item_t__ current;
- unsigned current_size;
- };
-
- enum phantom_point_index_t
- {
- PHANTOM_LEFT = 0,
- PHANTOM_RIGHT = 1,
- PHANTOM_TOP = 2,
- PHANTOM_BOTTOM = 3,
- PHANTOM_COUNT = 4
- };
-
- struct accelerator_t;
-
- struct Glyph
- {
- enum simple_glyph_flag_t
- {
- FLAG_ON_CURVE = 0x01,
- FLAG_X_SHORT = 0x02,
- FLAG_Y_SHORT = 0x04,
- FLAG_REPEAT = 0x08,
- FLAG_X_SAME = 0x10,
- FLAG_Y_SAME = 0x20,
- FLAG_OVERLAP_SIMPLE = 0x40,
- FLAG_RESERVED2 = 0x80
- };
-
- private:
- struct GlyphHeader
- {
- bool has_data () const { return numberOfContours; }
-
- bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
- hb_codepoint_t gid, hb_glyph_extents_t *extents) const
- {
- /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
- /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
- extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
- extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
- extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
- extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
-
- return true;
- }
-
- HBINT16 numberOfContours;
- /* If the number of contours is
- * greater than or equal to zero,
- * this is a simple glyph; if negative,
- * this is a composite glyph. */
- FWORD xMin; /* Minimum x for coordinate data. */
- FWORD yMin; /* Minimum y for coordinate data. */
- FWORD xMax; /* Maximum x for coordinate data. */
- FWORD yMax; /* Maximum y for coordinate data. */
- public:
- DEFINE_SIZE_STATIC (10);
- };
-
- struct SimpleGlyph
- {
- const GlyphHeader &header;
- hb_bytes_t bytes;
- SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
- header (header_), bytes (bytes_) {}
-
- unsigned int instruction_len_offset () const
- { return GlyphHeader::static_size + 2 * header.numberOfContours; }
-
- unsigned int length (unsigned int instruction_len) const
- { return instruction_len_offset () + 2 + instruction_len; }
-
- unsigned int instructions_length () const
- {
- unsigned int instruction_length_offset = instruction_len_offset ();
- if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
-
- const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
- /* Out of bounds of the current glyph */
- if (unlikely (length (instructionLength) > bytes.length)) return 0;
- return instructionLength;
- }
-
- const Glyph trim_padding () const
- {
- /* based on FontTools _g_l_y_f.py::trim */
- const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
- const uint8_t *glyph_end = glyph + bytes.length;
- /* simple glyph w/contours, possibly trimmable */
- glyph += instruction_len_offset ();
-
- if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
- unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
- unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
-
- glyph += 2 + num_instructions;
-
- unsigned int coord_bytes = 0;
- unsigned int coords_with_flags = 0;
- while (glyph < glyph_end)
- {
- uint8_t flag = *glyph;
- glyph++;
-
- unsigned int repeat = 1;
- if (flag & FLAG_REPEAT)
- {
- if (unlikely (glyph >= glyph_end)) return Glyph ();
- repeat = *glyph + 1;
- glyph++;
- }
-
- unsigned int xBytes, yBytes;
- xBytes = yBytes = 0;
- if (flag & FLAG_X_SHORT) xBytes = 1;
- else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
-
- if (flag & FLAG_Y_SHORT) yBytes = 1;
- else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
-
- coord_bytes += (xBytes + yBytes) * repeat;
- coords_with_flags += repeat;
- if (coords_with_flags >= num_coordinates) break;
- }
-
- if (unlikely (coords_with_flags != num_coordinates)) return Glyph ();
- return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)));
- }
-
- /* zero instruction length */
- void drop_hints ()
- {
- GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
- (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
- }
-
- void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
- {
- unsigned int instructions_len = instructions_length ();
- unsigned int glyph_length = length (instructions_len);
- dest_start = bytes.sub_array (0, glyph_length - instructions_len);
- dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
- }
-
- void set_overlaps_flag ()
- {
- if (unlikely (!header.numberOfContours)) return;
-
- unsigned flags_offset = length (instructions_length ());
- 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;
- }
-
- static bool read_points (const HBUINT8 *&p /* IN/OUT */,
- contour_point_vector_t &points_ /* IN/OUT */,
- const hb_bytes_t &bytes,
- void (* setter) (contour_point_t &_, float v),
- const simple_glyph_flag_t short_flag,
- const simple_glyph_flag_t same_flag)
- {
- float v = 0;
- for (unsigned i = 0; i < points_.length; i++)
- {
- uint8_t flag = points_[i].flag;
- if (flag & short_flag)
- {
- if (unlikely (!bytes.check_range (p))) return false;
- if (flag & same_flag)
- v += *p++;
- else
- v -= *p++;
- }
- else
- {
- if (!(flag & same_flag))
- {
- if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false;
- v += *(const HBINT16 *) p;
- p += HBINT16::static_size;
- }
- }
- setter (points_[i], v);
- }
- return true;
- }
-
- bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
- bool phantom_only = false) const
- {
- const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
- int num_contours = header.numberOfContours;
- if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
- unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
-
- points_.resize (num_points);
- for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
- if (phantom_only) return true;
-
- for (int i = 0; i < num_contours; i++)
- points_[endPtsOfContours[i]].is_end_point = true;
-
- /* Skip instructions */
- const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
- endPtsOfContours[num_contours]);
-
- /* Read flags */
- for (unsigned int i = 0; i < num_points; i++)
- {
- if (unlikely (!bytes.check_range (p))) return false;
- uint8_t flag = *p++;
- points_[i].flag = flag;
- if (flag & FLAG_REPEAT)
- {
- if (unlikely (!bytes.check_range (p))) return false;
- unsigned int repeat_count = *p++;
- while ((repeat_count-- > 0) && (++i < num_points))
- points_[i].flag = flag;
- }
- }
-
- /* Read x & y coordinates */
- return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; },
- FLAG_X_SHORT, FLAG_X_SAME)
- && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; },
- FLAG_Y_SHORT, FLAG_Y_SAME);
- }
- };
-
- struct CompositeGlyph
- {
- const GlyphHeader &header;
- hb_bytes_t bytes;
- CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
- header (header_), bytes (bytes_) {}
-
- composite_iter_t get_iterator () const
- { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); }
-
- unsigned int instructions_length (hb_bytes_t bytes) const
- {
- unsigned int start = bytes.length;
- unsigned int end = bytes.length;
- const CompositeGlyphChain *last = nullptr;
- for (auto &item : get_iterator ())
- last = &item;
- if (unlikely (!last)) return 0;
-
- if (last->has_instructions ())
- start = (char *) last - &bytes + last->get_size ();
- if (unlikely (start > end)) return 0;
- return end - start;
- }
-
- /* Trimming for composites not implemented.
- * If removing hints it falls out of that. */
- const Glyph trim_padding () const { return Glyph (bytes); }
-
- void drop_hints ()
- {
- for (const auto &_ : get_iterator ())
- const_cast<CompositeGlyphChain &> (_).drop_instructions_flag ();
- }
-
- /* Chop instructions off the end */
- void drop_hints_bytes (hb_bytes_t &dest_start) const
- { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
-
- void set_overlaps_flag ()
- {
- const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
- .set_overlaps_flag ();
- }
- };
-
- enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
-
- public:
- composite_iter_t get_composite_iterator () const
- {
- if (type != COMPOSITE) return composite_iter_t ();
- return CompositeGlyph (*header, bytes).get_iterator ();
- }
-
- const Glyph trim_padding () const
- {
- switch (type) {
- case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
- case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
- default: return bytes;
- }
- }
-
- void drop_hints ()
- {
- switch (type) {
- case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
- case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
- default: return;
- }
- }
-
- void set_overlaps_flag ()
- {
- switch (type) {
- case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
- case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
- default: return;
- }
- }
-
- void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
- {
- switch (type) {
- case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
- case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
- default: return;
- }
- }
-
- /* Note: Recursively calls itself.
- * all_points includes phantom points
- */
- bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
- contour_point_vector_t &all_points /* OUT */,
- bool phantom_only = false,
- unsigned int depth = 0) const
- {
- if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
- contour_point_vector_t points;
-
- switch (type) {
- case COMPOSITE:
- {
- /* pseudo component points for each component in composite glyph */
- unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ());
- if (unlikely (!points.resize (num_points))) return false;
- for (unsigned i = 0; i < points.length; i++)
- points[i].init ();
- break;
- }
- case SIMPLE:
- if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
- return false;
- break;
- }
-
- /* Init phantom points */
- if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
- hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
- {
- for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
- int h_delta = (int) header->xMin -
- glyf_accelerator.hmtx->get_side_bearing (gid);
- int v_orig = (int) header->yMax +
-#ifndef HB_NO_VERTICAL
- glyf_accelerator.vmtx->get_side_bearing (gid)
-#else
- 0
-#endif
- ;
- unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
- unsigned v_adv =
-#ifndef HB_NO_VERTICAL
- glyf_accelerator.vmtx->get_advance (gid)
-#else
- - font->face->get_upem ()
-#endif
- ;
- phantoms[PHANTOM_LEFT].x = h_delta;
- phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
- phantoms[PHANTOM_TOP].y = v_orig;
- phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
- }
-
-#ifndef HB_NO_VAR
- glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
-#endif
-
- switch (type) {
- case SIMPLE:
- all_points.extend (points.as_array ());
- break;
- case COMPOSITE:
- {
- unsigned int comp_index = 0;
- for (auto &item : get_composite_iterator ())
- {
- contour_point_vector_t comp_points;
- if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ())
- .get_points (font, glyf_accelerator, comp_points,
- phantom_only, depth + 1)
- || comp_points.length < PHANTOM_COUNT))
- return false;
-
- /* Copy phantom points from component if USE_MY_METRICS flag set */
- if (item.is_use_my_metrics ())
- for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
- phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
-
- /* Apply component transformation & translation */
- item.transform_points (comp_points);
-
- /* Apply translation from gvar */
- comp_points.translate (points[comp_index]);
-
- if (item.is_anchored ())
- {
- unsigned int p1, p2;
- item.get_anchor_points (p1, p2);
- if (likely (p1 < all_points.length && p2 < comp_points.length))
- {
- contour_point_t delta;
- delta.init (all_points[p1].x - comp_points[p2].x,
- all_points[p1].y - comp_points[p2].y);
-
- comp_points.translate (delta);
- }
- }
-
- all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
-
- comp_index++;
- }
-
- all_points.extend (phantoms);
- } break;
- default:
- all_points.extend (phantoms);
- }
-
- if (depth == 0) /* Apply at top level */
- {
- /* Undocumented rasterizer behavior:
- * Shift points horizontally by the updated left side bearing
- */
- contour_point_t delta;
- delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
- if (delta.x) all_points.translate (delta);
- }
-
- return true;
- }
-
- bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
- hb_glyph_extents_t *extents) const
- {
- if (type == EMPTY) return true; /* Empty glyph; zero extents. */
- return header->get_extents (font, glyf_accelerator, gid, extents);
- }
-
- hb_bytes_t get_bytes () const { return bytes; }
-
- Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
- hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_),
- header (bytes.as<GlyphHeader> ())
- {
- int num_contours = header->numberOfContours;
- if (unlikely (num_contours == 0)) type = EMPTY;
- else if (num_contours > 0) type = SIMPLE;
- else type = COMPOSITE; /* negative numbers */
- }
-
- protected:
- hb_bytes_t bytes;
- hb_codepoint_t gid;
- const GlyphHeader *header;
- unsigned type;
- };
-
- struct accelerator_t
- {
- accelerator_t (hb_face_t *face)
- {
- short_offset = false;
- num_glyphs = 0;
- loca_table = nullptr;
- glyf_table = nullptr;
-#ifndef HB_NO_VAR
- gvar = nullptr;
-#endif
- hmtx = nullptr;
-#ifndef HB_NO_VERTICAL
- vmtx = nullptr;
-#endif
- 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 = 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;
-#endif
- hmtx = face->table.hmtx;
-#ifndef HB_NO_VERTICAL
- vmtx = face->table.vmtx;
-#endif
-
- num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
- num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
- }
- ~accelerator_t ()
- {
- glyf_table.destroy ();
- }
-
- protected:
- template<typename T>
- bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
- {
- if (gid >= num_glyphs) return false;
-
- /* Making this allocfree is not that easy
- https://github.com/harfbuzz/harfbuzz/issues/2095
- mostly because of gvar handling in VF fonts,
- perhaps a separate path for non-VF fonts can be considered */
- contour_point_vector_t all_points;
-
- bool phantom_only = !consumer.is_consuming_contour_points ();
- if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
- return false;
-
- if (consumer.is_consuming_contour_points ())
- {
- for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index)
- consumer.consume_point (all_points[point_index]);
- consumer.points_end ();
- }
-
- /* Where to write phantoms, nullptr if not requested */
- contour_point_t *phantoms = consumer.get_phantoms_sink ();
- if (phantoms)
- for (unsigned i = 0; i < PHANTOM_COUNT; ++i)
- phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i];
-
- return true;
- }
-
-#ifndef HB_NO_VAR
- struct points_aggregator_t
- {
- hb_font_t *font;
- hb_glyph_extents_t *extents;
- contour_point_t *phantoms;
-
- struct contour_bounds_t
- {
- contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
-
- void add (const contour_point_t &p)
- {
- min_x = hb_min (min_x, p.x);
- min_y = hb_min (min_y, p.y);
- max_x = hb_max (max_x, p.x);
- max_y = hb_max (max_y, p.y);
- }
-
- bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
-
- void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
- {
- if (unlikely (empty ()))
- {
- extents->width = 0;
- extents->x_bearing = 0;
- extents->height = 0;
- extents->y_bearing = 0;
- return;
- }
- extents->x_bearing = font->em_scalef_x (min_x);
- extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
- extents->y_bearing = font->em_scalef_y (max_y);
- extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
- }
-
- protected:
- float min_x, min_y, max_x, max_y;
- } bounds;
-
- points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
- {
- font = font_;
- extents = extents_;
- phantoms = phantoms_;
- if (extents) bounds = contour_bounds_t ();
- }
-
- void consume_point (const contour_point_t &point) { bounds.add (point); }
- void points_end () { bounds.get_extents (font, extents); }
-
- bool is_consuming_contour_points () { return extents; }
- contour_point_t *get_phantoms_sink () { return phantoms; }
- };
-
- public:
- unsigned
- get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
- {
- if (unlikely (gid >= num_glyphs)) return 0;
-
- bool success = false;
-
- contour_point_t phantoms[PHANTOM_COUNT];
- if (likely (font->num_coords == gvar->get_axis_count ()))
- success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
-
- if (unlikely (!success))
- return
-#ifndef HB_NO_VERTICAL
- is_vertical ? vmtx->get_advance (gid) :
-#endif
- hmtx->get_advance (gid);
-
- float result = is_vertical
- ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y
- : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x;
- return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
- }
-
- int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
- {
- if (unlikely (gid >= num_glyphs)) return 0;
-
- hb_glyph_extents_t extents;
-
- contour_point_t phantoms[PHANTOM_COUNT];
- if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
- return
-#ifndef HB_NO_VERTICAL
- is_vertical ? vmtx->get_side_bearing (gid) :
-#endif
- hmtx->get_side_bearing (gid);
-
- return is_vertical
- ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing
- : floorf (phantoms[PHANTOM_LEFT].x);
- }
-#endif
-
- public:
- bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
- {
- if (unlikely (gid >= num_glyphs)) return false;
-
-#ifndef HB_NO_VAR
- if (font->num_coords && font->num_coords == gvar->get_axis_count ())
- return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
-#endif
- return glyph_for_gid (gid).get_extents (font, *this, extents);
- }
-
- const Glyph
- glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
- {
- if (unlikely (gid >= num_glyphs)) return Glyph ();
-
- unsigned int start_offset, end_offset;
-
- if (short_offset)
- {
- const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
- start_offset = 2 * offsets[gid];
- end_offset = 2 * offsets[gid + 1];
- }
- else
- {
- const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
- start_offset = offsets[gid];
- end_offset = offsets[gid + 1];
- }
-
- if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
- return Glyph ();
-
- Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
- end_offset - start_offset), gid);
- return needs_padding_removal ? glyph.trim_padding () : glyph;
- }
-
- unsigned
- add_gid_and_children (hb_codepoint_t gid,
- hb_set_t *gids_to_retain,
- unsigned depth = 0,
- unsigned operation_count = 0) const
- {
- if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
- if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count;
- /* Check if is already visited */
- if (gids_to_retain->has (gid)) return operation_count;
-
- gids_to_retain->add (gid);
-
- auto it = glyph_for_gid (gid).get_composite_iterator ();
- while (it)
- {
- auto item = *(it++);
- operation_count =
- add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count);
- }
-
- return operation_count;
- }
-
- struct path_builder_t
- {
- hb_font_t *font;
- hb_draw_session_t *draw_session;
-
- struct optional_point_t
- {
- optional_point_t () { has_data = false; }
- optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; }
-
- bool has_data;
- float x;
- float y;
-
- optional_point_t lerp (optional_point_t p, float t)
- { 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_, hb_draw_session_t &draw_session_)
- {
- font = font_;
- draw_session = &draw_session_;
- first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
- }
-
- /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
- See also:
- * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
- * https://stackoverflow.com/a/20772557 */
- void consume_point (const contour_point_t &point)
- {
- bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
- optional_point_t p (point.x, point.y);
- if (!first_oncurve.has_data)
- {
- if (is_on_curve)
- {
- first_oncurve = p;
- draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
- }
- else
- {
- if (first_offcurve.has_data)
- {
- optional_point_t mid = first_offcurve.lerp (p, .5f);
- first_oncurve = mid;
- last_offcurve = p;
- draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
- }
- else
- first_offcurve = p;
- }
- }
- else
- {
- if (last_offcurve.has_data)
- {
- if (is_on_curve)
- {
- 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_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_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
- else
- last_offcurve = p;
- }
- }
-
- if (point.is_end_point)
- {
- if (first_offcurve.has_data && last_offcurve.has_data)
- {
- optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
- 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_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_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_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_session->close_path ();
- }
- }
- void points_end () {}
-
- bool is_consuming_contour_points () { return true; }
- contour_point_t *get_phantoms_sink () { return nullptr; }
- };
-
- bool
- 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;
-#endif
- const hmtx_accelerator_t *hmtx;
-#ifndef HB_NO_VERTICAL
- const vmtx_accelerator_t *vmtx;
-#endif
-
- private:
- bool short_offset;
- unsigned int num_glyphs;
- hb_blob_ptr_t<loca> loca_table;
- hb_blob_ptr_t<glyf> glyf_table;
- };
-
- struct SubsetGlyph
- {
- hb_codepoint_t new_gid;
- hb_codepoint_t old_gid;
- Glyph source_glyph;
- hb_bytes_t dest_start; /* region of source_glyph to copy first */
- hb_bytes_t dest_end; /* region of source_glyph to copy second */
-
- bool serialize (hb_serialize_context_t *c,
- bool use_short_loca,
- const hb_subset_plan_t *plan) const
- {
- TRACE_SERIALIZE (this);
-
- hb_bytes_t dest_glyph = dest_start.copy (c);
- dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
- unsigned int pad_length = use_short_loca ? padding () : 0;
- DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
-
- HBUINT8 pad;
- pad = 0;
- while (pad_length > 0)
- {
- c->embed (pad);
- pad_length--;
- }
-
- if (unlikely (!dest_glyph.length)) return_trace (true);
-
- /* update components gids */
- for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
- {
- hb_codepoint_t new_gid;
- if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid))
- const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
- }
-
- if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- Glyph (dest_glyph).drop_hints ();
-
- if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
- Glyph (dest_glyph).set_overlaps_flag ();
-
- return_trace (true);
- }
-
- void drop_hints_bytes ()
- { source_glyph.drop_hints_bytes (dest_start, dest_end); }
-
- unsigned int length () const { return dest_start.length + dest_end.length; }
- /* pad to 2 to ensure 2-byte loca will be ok */
- unsigned int padding () const { return length () % 2; }
- unsigned int padded_size () const { return length () + padding (); }
- };
-
- protected:
- UnsizedArrayOf<HBUINT8>
- dataZ; /* Glyphs data. */
- public:
- DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
- * check the size externally, allow Null() object of it by
- * defining it _MIN instead. */
-};
-
-struct glyf_accelerator_t : glyf::accelerator_t {
- glyf_accelerator_t (hb_face_t *face) : glyf::accelerator_t (face) {}
-};
-
-
-} /* namespace OT */
-
+#include "OT/glyf/glyf.hh"
#endif /* HB_OT_GLYF_TABLE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
index d5e1fc91d2..d0e46e0b0f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -242,7 +242,7 @@ struct hmtxvmtx
return side_bearing;
if (var_table.get_length ())
- return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+ return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords);
return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
#else
@@ -284,7 +284,8 @@ struct hmtxvmtx
}
unsigned int get_advance (hb_codepoint_t glyph,
- hb_font_t *font) const
+ hb_font_t *font,
+ VariationStore::cache_t *store_cache = nullptr) const
{
unsigned int advance = get_advance (glyph);
@@ -293,7 +294,7 @@ struct hmtxvmtx
return advance;
if (var_table.get_length ())
- return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
+ return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?!
return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
#else
@@ -310,7 +311,7 @@ struct hmtxvmtx
unsigned int default_advance;
- private:
+ public:
hb_blob_ptr_t<hmtxvmtx> table;
hb_blob_ptr_t<HVARVVAR> var_table;
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index f2a58028e3..d343805346 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -91,18 +91,18 @@ 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
{
hb_prune_langsys_context_t (const void *table_,
- hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_,
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
const hb_map_t *duplicate_feature_map_,
hb_set_t *new_collected_feature_indexes_)
:table (table_),
@@ -122,7 +122,7 @@ struct hb_prune_langsys_context_t
public:
const void *table;
- hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
const hb_map_t *duplicate_feature_map;
hb_set_t *new_feature_indexes;
@@ -162,14 +162,14 @@ struct hb_subset_layout_context_t :
hb_subset_context_t *subset_context;
const hb_tag_t table_tag;
const hb_map_t *lookup_index_map;
- const hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map;
+ const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
const hb_map_t *feature_index_map;
unsigned cur_script_index;
hb_subset_layout_context_t (hb_subset_context_t *c_,
hb_tag_t tag_,
hb_map_t *lookup_map_,
- hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_,
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
hb_map_t *feature_index_map_) :
subset_context (c_),
table_tag (tag_),
@@ -659,7 +659,8 @@ struct LangSys
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
+ const unsigned *v;
+ out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
if (!l->visitFeatureIndex (featureIndex.len))
return_trace (false);
@@ -722,12 +723,8 @@ struct Script
if (!c->script_langsys_map->has (script_index))
{
- hb_set_t* empty_set = hb_set_create ();
- if (unlikely (!c->script_langsys_map->set (script_index, empty_set)))
- {
- hb_set_destroy (empty_set);
+ if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
return;
- }
}
unsigned langsys_count = get_lang_sys_count ();
@@ -1470,7 +1467,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;
@@ -1506,12 +1504,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;
@@ -1524,6 +1516,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;
@@ -1552,25 +1545,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;
}
@@ -1579,8 +1573,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);
}
}
@@ -1632,6 +1628,8 @@ struct CoverageFormat2
return;
}
}
+ else
+ j = 0;
return;
}
coverage++;
@@ -1639,7 +1637,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;
@@ -1708,18 +1714,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
@@ -1822,7 +1827,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;
@@ -1830,6 +1835,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;
@@ -1857,16 +1874,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;
}
@@ -1883,17 +1898,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 ());
}
/*
@@ -1949,36 +1962,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
@@ -1987,6 +2001,8 @@ struct ClassDefFormat1
return_trace (c->check_struct (this) && classValue.sanitize (c));
}
+ unsigned cost () const { return 1; }
+
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
@@ -2044,10 +2060,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;
}
@@ -2057,17 +2072,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
@@ -2167,12 +2197,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++)
@@ -2183,21 +2211,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
@@ -2206,6 +2239,8 @@ struct ClassDefFormat2
return_trace (rangeRecord.sanitize (c));
}
+ unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
+
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
@@ -2263,10 +2298,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;
}
@@ -2279,43 +2313,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);
}
}
@@ -2446,6 +2481,15 @@ struct ClassDef
}
}
+ unsigned cost () const
+ {
+ switch (u.format) {
+ case 1: return u.format1.cost ();
+ case 2: return u.format2.cost ();
+ default:return 0u;
+ }
+ }
+
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
@@ -2567,14 +2611,27 @@ struct VarRegionAxis
DEFINE_SIZE_STATIC (6);
};
+#define REGION_CACHE_ITEM_CACHE_INVALID 2.f
+
struct VarRegionList
{
+ using cache_t = float;
+
float evaluate (unsigned int region_index,
- const int *coords, unsigned int coord_len) const
+ const int *coords, unsigned int coord_len,
+ cache_t *cache = nullptr) const
{
if (unlikely (region_index >= regionCount))
return 0.;
+ float *cached_value = nullptr;
+ if (cache)
+ {
+ cached_value = &(cache[region_index]);
+ if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
+ return *cached_value;
+ }
+
const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
float v = 1.;
@@ -2584,9 +2641,16 @@ struct VarRegionList
int coord = i < coord_len ? coords[i] : 0;
float factor = axes[i].evaluate (coord);
if (factor == 0.f)
+ {
+ if (cache)
+ *cached_value = 0.;
return 0.;
+ }
v *= factor;
}
+
+ if (cache)
+ *cached_value = v;
return v;
}
@@ -2634,7 +2698,7 @@ struct VarData
{ return regionIndices.len; }
unsigned int get_row_size () const
- { return shortCount + regionIndices.len; }
+ { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
unsigned int get_size () const
{ return min_size
@@ -2644,13 +2708,17 @@ struct VarData
float get_delta (unsigned int inner,
const int *coords, unsigned int coord_count,
- const VarRegionList &regions) const
+ const VarRegionList &regions,
+ VarRegionList::cache_t *cache = nullptr) const
{
if (unlikely (inner >= itemCount))
return 0.;
unsigned int count = regionIndices.len;
- unsigned int scount = shortCount;
+ bool is_long = longWords ();
+ unsigned word_count = wordCount ();
+ unsigned int scount = is_long ? count - word_count : word_count;
+ unsigned int lcount = is_long ? word_count : 0;
const HBUINT8 *bytes = get_delta_bytes ();
const HBUINT8 *row = bytes + inner * (scount + count);
@@ -2658,16 +2726,22 @@ struct VarData
float delta = 0.;
unsigned int i = 0;
- const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
+ const HBINT16 *lcursor = reinterpret_cast<const HBINT16 *> (row);
+ for (; i < lcount; i++)
+ {
+ float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
+ delta += scalar * *lcursor++;
+ }
+ const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (lcursor);
for (; i < scount; i++)
{
- float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+ float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
delta += scalar * *scursor++;
}
const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
for (; i < count; i++)
{
- float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+ float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
delta += scalar * *bcursor++;
}
@@ -2691,7 +2765,7 @@ struct VarData
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
regionIndices.sanitize (c) &&
- shortCount <= regionIndices.len &&
+ wordCount () <= regionIndices.len &&
c->check_range (get_delta_bytes (),
itemCount,
get_row_size ()));
@@ -2706,43 +2780,66 @@ struct VarData
if (unlikely (!c->extend_min (this))) return_trace (false);
itemCount = inner_map.get_next_value ();
- /* Optimize short count */
- unsigned short ri_count = src->regionIndices.len;
- enum delta_size_t { kZero=0, kByte, kShort };
+ /* Optimize word count */
+ unsigned ri_count = src->regionIndices.len;
+ enum delta_size_t { kZero=0, kNonWord, kWord };
hb_vector_t<delta_size_t> delta_sz;
hb_vector_t<unsigned int> ri_map; /* maps old index to new index */
delta_sz.resize (ri_count);
ri_map.resize (ri_count);
- unsigned int new_short_count = 0;
+ unsigned int new_word_count = 0;
unsigned int r;
+
+ bool has_long = false;
+ if (src->longWords ())
+ {
+ for (r = 0; r < ri_count; r++)
+ {
+ for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+ {
+ unsigned int old = inner_map.backward (i);
+ int32_t delta = src->get_item_delta (old, r);
+ if (delta < -65536 || 65535 < delta)
+ {
+ has_long = true;
+ break;
+ }
+ }
+ }
+ }
+
+ signed min_threshold = has_long ? -65536 : -128;
+ signed max_threshold = has_long ? +65535 : +127;
for (r = 0; r < ri_count; r++)
{
delta_sz[r] = kZero;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
{
unsigned int old = inner_map.backward (i);
- int16_t delta = src->get_item_delta (old, r);
- if (delta < -128 || 127 < delta)
+ int32_t delta = src->get_item_delta (old, r);
+ if (delta < min_threshold || max_threshold < delta)
{
- delta_sz[r] = kShort;
- new_short_count++;
+ delta_sz[r] = kWord;
+ new_word_count++;
break;
}
else if (delta != 0)
- delta_sz[r] = kByte;
+ delta_sz[r] = kNonWord;
}
}
- unsigned int short_index = 0;
- unsigned int byte_index = new_short_count;
+
+ unsigned int word_index = 0;
+ unsigned int non_word_index = new_word_count;
unsigned int new_ri_count = 0;
for (r = 0; r < ri_count; r++)
if (delta_sz[r])
{
- ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
+ ri_map[r] = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
new_ri_count++;
}
- shortCount = new_short_count;
+ wordSizeCount = new_word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
+
regionIndices.len = new_ri_count;
if (unlikely (!c->extend (this))) return_trace (false);
@@ -2782,28 +2879,55 @@ struct VarData
HBUINT8 *get_delta_bytes ()
{ return &StructAfter<HBUINT8> (regionIndices); }
- int16_t get_item_delta (unsigned int item, unsigned int region) const
+ int32_t get_item_delta (unsigned int item, unsigned int region) const
{
if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0;
- const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size ();
- if (region < shortCount)
- return ((const HBINT16 *)p)[region];
+ const HBINT8 *p = (const HBINT8 *) get_delta_bytes () + item * get_row_size ();
+ unsigned word_count = wordCount ();
+ bool is_long = longWords ();
+ if (is_long)
+ {
+ if (region < word_count)
+ return ((const HBINT32 *) p)[region];
+ else
+ return ((const HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count];
+ }
else
- return (p + HBINT16::static_size * shortCount)[region - shortCount];
+ {
+ if (region < word_count)
+ return ((const HBINT16 *) p)[region];
+ else
+ return (p + HBINT16::static_size * word_count)[region - word_count];
+ }
}
- void set_item_delta (unsigned int item, unsigned int region, int16_t delta)
+ void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
{
HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
- if (region < shortCount)
- ((HBINT16 *)p)[region] = delta;
+ unsigned word_count = wordCount ();
+ bool is_long = longWords ();
+ if (is_long)
+ {
+ if (region < word_count)
+ ((HBINT32 *) p)[region] = delta;
+ else
+ ((HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count] = delta;
+ }
else
- (p + HBINT16::static_size * shortCount)[region - shortCount] = delta;
+ {
+ if (region < word_count)
+ ((HBINT16 *) p)[region] = delta;
+ else
+ (p + HBINT16::static_size * word_count)[region - word_count] = delta;
+ }
}
+ bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; }
+ unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; }
+
protected:
HBUINT16 itemCount;
- HBUINT16 shortCount;
+ HBUINT16 wordSizeCount;
Array16Of<HBUINT16> regionIndices;
/*UnsizedArrayOf<HBUINT8>bytesX;*/
public:
@@ -2812,9 +2936,28 @@ struct VarData
struct VariationStore
{
+ using cache_t = VarRegionList::cache_t;
+
+ cache_t *create_cache () const
+ {
+ auto &r = this+regions;
+ unsigned count = r.regionCount;
+
+ float *cache = (float *) hb_malloc (sizeof (float) * count);
+ if (unlikely (!cache)) return nullptr;
+
+ for (unsigned i = 0; i < count; i++)
+ cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
+
+ return cache;
+ }
+
+ static void destroy_cache (cache_t *cache) { hb_free (cache); }
+
private:
float get_delta (unsigned int outer, unsigned int inner,
- const int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count,
+ VarRegionList::cache_t *cache = nullptr) const
{
#ifdef HB_NO_VAR
return 0.f;
@@ -2825,16 +2968,18 @@ struct VariationStore
return (this+dataSets[outer]).get_delta (inner,
coords, coord_count,
- this+regions);
+ this+regions,
+ cache);
}
public:
float get_delta (unsigned int index,
- const int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count,
+ VarRegionList::cache_t *cache = nullptr) const
{
unsigned int outer = index >> 16;
unsigned int inner = index & 0xFFFF;
- return get_delta (outer, inner, coords, coord_count);
+ return get_delta (outer, inner, coords, coord_count, cache);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2961,6 +3106,8 @@ struct VariationStore
DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
};
+#undef REGION_CACHE_ITEM_CACHE_INVALID
+
/*
* Feature Variations
*/
@@ -3428,11 +3575,15 @@ struct VariationDevice
private:
- hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
- { return font->em_scalef_x (get_delta (font, store)); }
+ hb_position_t get_x_delta (hb_font_t *font,
+ const VariationStore &store,
+ VariationStore::cache_t *store_cache = nullptr) const
+ { return font->em_scalef_x (get_delta (font, store, store_cache)); }
- hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
- { return font->em_scalef_y (get_delta (font, store)); }
+ hb_position_t get_y_delta (hb_font_t *font,
+ const VariationStore &store,
+ VariationStore::cache_t *store_cache = nullptr) const
+ { return font->em_scalef_y (get_delta (font, store, store_cache)); }
VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
{
@@ -3466,9 +3617,11 @@ struct VariationDevice
private:
- float get_delta (hb_font_t *font, const VariationStore &store) const
+ float get_delta (hb_font_t *font,
+ const VariationStore &store,
+ VariationStore::cache_t *store_cache = nullptr) const
{
- return store.get_delta (varIdx, font->coords, font->num_coords);
+ return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
}
protected:
@@ -3491,7 +3644,9 @@ struct DeviceHeader
struct Device
{
- hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
+ hb_position_t get_x_delta (hb_font_t *font,
+ const VariationStore &store=Null (VariationStore),
+ VariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
@@ -3501,13 +3656,15 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- return u.variation.get_x_delta (font, store);
+ return u.variation.get_x_delta (font, store, store_cache);
#endif
default:
return 0;
}
}
- hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
+ hb_position_t get_y_delta (hb_font_t *font,
+ const VariationStore &store=Null (VariationStore),
+ VariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
@@ -3517,7 +3674,7 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- return u.variation.get_y_delta (font, store);
+ return u.variation.get_y_delta (font, store, store_cache);
#endif
default:
return 0;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
index a76d644c4b..9d47bac2b9 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -571,7 +571,7 @@ struct GDEF
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
switch (klass) {
- default: return 0;
+ default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
index 2f9186a2a7..064d31cdff 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -29,3090 +29,14 @@
#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
#define HB_OT_LAYOUT_GPOS_TABLE_HH
-#include "hb-ot-layout-gsubgpos.hh"
-
+#include "OT/Layout/GPOS.hh"
namespace OT {
-struct MarkArray;
-static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
- const MarkArray &mark_array,
- const hb_set_t &glyphset,
- hb_map_t* klass_mapping /* INOUT */);
-
-/* buffer **position** var allocations */
-#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
-#define attach_type() var.u8[2] /* attachment type */
-/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
-
-enum attach_type_t {
- ATTACH_TYPE_NONE = 0X00,
-
- /* Each attachment should be either a mark or a cursive; can't be both. */
- ATTACH_TYPE_MARK = 0X01,
- ATTACH_TYPE_CURSIVE = 0X02,
-};
-
-
-/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
-
-typedef HBUINT16 Value;
-
-typedef UnsizedArrayOf<Value> ValueRecord;
-
-struct ValueFormat : HBUINT16
-{
- enum Flags {
- xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
- yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
- xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
- yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
- xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
- yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
- xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
- yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
- ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
- reserved = 0xF000u, /* For future use */
-
- devices = 0x00F0u /* Mask for having any Device table */
- };
-
-/* All fields are options. Only those available advance the value pointer. */
-#if 0
- HBINT16 xPlacement; /* Horizontal adjustment for
- * placement--in design units */
- HBINT16 yPlacement; /* Vertical adjustment for
- * placement--in design units */
- HBINT16 xAdvance; /* Horizontal adjustment for
- * advance--in design units (only used
- * for horizontal writing) */
- HBINT16 yAdvance; /* Vertical adjustment for advance--in
- * design units (only used for vertical
- * writing) */
- Offset16To<Device> xPlaDevice; /* Offset to Device table for
- * horizontal placement--measured from
- * beginning of PosTable (may be NULL) */
- Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical
- * placement--measured from beginning
- * of PosTable (may be NULL) */
- Offset16To<Device> xAdvDevice; /* Offset to Device table for
- * horizontal advance--measured from
- * beginning of PosTable (may be NULL) */
- Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical
- * advance--measured from beginning of
- * PosTable (may be NULL) */
-#endif
-
- IntType& operator = (uint16_t i) { v = i; return *this; }
-
- unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
- unsigned int get_size () const { return get_len () * Value::static_size; }
-
- bool apply_value (hb_ot_apply_context_t *c,
- const void *base,
- const Value *values,
- hb_glyph_position_t &glyph_pos) const
- {
- bool ret = false;
- unsigned int format = *this;
- if (!format) return ret;
-
- hb_font_t *font = c->font;
- bool horizontal =
-#ifndef HB_NO_VERTICAL
- HB_DIRECTION_IS_HORIZONTAL (c->direction)
-#else
- true
-#endif
- ;
-
- if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret));
- if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret));
- if (format & xAdvance) {
- if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
- values++;
- }
- /* y_advance values grow downward but font-space grows upward, hence negation */
- if (format & yAdvance) {
- if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
- values++;
- }
-
- if (!has_device ()) return ret;
-
- bool use_x_device = font->x_ppem || font->num_coords;
- bool use_y_device = font->y_ppem || font->num_coords;
-
- if (!use_x_device && !use_y_device) return ret;
-
- const VariationStore &store = c->var_store;
-
- /* pixel -> fractional pixel */
- if (format & xPlaDevice) {
- if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store);
- values++;
- }
- if (format & yPlaDevice) {
- if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store);
- values++;
- }
- if (format & xAdvDevice) {
- if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store);
- values++;
- }
- if (format & yAdvDevice) {
- /* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store);
- values++;
- }
- return ret;
- }
-
- unsigned int get_effective_format (const Value *values) const
- {
- unsigned int format = *this;
- for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
- if (format & flag) should_drop (*values++, (Flags) flag, &format);
- }
-
- return format;
- }
-
- template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- unsigned int get_effective_format (Iterator it) const {
- unsigned int new_format = 0;
-
- for (const hb_array_t<const Value>& values : it)
- new_format = new_format | get_effective_format (&values);
-
- return new_format;
- }
-
- void copy_values (hb_serialize_context_t *c,
- unsigned int new_format,
- const void *base,
- const Value *values,
- const hb_map_t *layout_variation_idx_map) const
- {
- unsigned int format = *this;
- if (!format) return;
-
- if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
- if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
- if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++);
- if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++);
-
- if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
- if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
- }
-
- void copy_value (hb_serialize_context_t *c,
- unsigned int new_format,
- Flags flag,
- Value value) const
- {
- // Filter by new format.
- if (!(new_format & flag)) return;
- c->copy (value);
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *base,
- const hb_array_t<const Value>& values) const
- {
- unsigned format = *this;
- unsigned i = 0;
- if (format & xPlacement) i++;
- if (format & yPlacement) i++;
- if (format & xAdvance) i++;
- if (format & yAdvance) i++;
- if (format & xPlaDevice)
- {
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
- i++;
- }
-
- if (format & ValueFormat::yPlaDevice)
- {
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
- i++;
- }
-
- if (format & ValueFormat::xAdvDevice)
- {
-
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
- i++;
- }
-
- if (format & ValueFormat::yAdvDevice)
- {
-
- (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
- i++;
- }
- }
-
- private:
- bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
- {
- unsigned int format = *this;
-
- if (format & xPlacement) values++;
- if (format & yPlacement) values++;
- if (format & xAdvance) values++;
- if (format & yAdvance) values++;
-
- if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
- if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
- if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
- if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
-
- return true;
- }
-
- static inline Offset16To<Device>& get_device (Value* value)
- {
- return *static_cast<Offset16To<Device> *> (value);
- }
- static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
- {
- if (worked) *worked |= bool (*value);
- return *static_cast<const Offset16To<Device> *> (value);
- }
-
- bool copy_device (hb_serialize_context_t *c, const void *base,
- const Value *src_value, const hb_map_t *layout_variation_idx_map) const
- {
- Value *dst_value = c->copy (*src_value);
-
- if (!dst_value) return false;
- if (*dst_value == 0) return true;
-
- *dst_value = 0;
- c->push ();
- if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
- {
- c->add_link (*dst_value, c->pop_pack ());
- return true;
- }
- else
- {
- c->pop_discard ();
- return false;
- }
- }
-
- static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
- {
- if (worked) *worked |= bool (*value);
- return *reinterpret_cast<const HBINT16 *> (value);
- }
-
- public:
-
- bool has_device () const
- {
- unsigned int format = *this;
- return (format & devices) != 0;
- }
-
- bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
- }
-
- bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
- {
- TRACE_SANITIZE (this);
- unsigned int len = get_len ();
-
- if (!c->check_range (values, count, get_size ())) return_trace (false);
-
- if (!has_device ()) return_trace (true);
-
- for (unsigned int i = 0; i < count; i++) {
- if (!sanitize_value_devices (c, base, values))
- return_trace (false);
- values += len;
- }
-
- return_trace (true);
- }
-
- /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
- bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
- {
- TRACE_SANITIZE (this);
-
- if (!has_device ()) return_trace (true);
-
- for (unsigned int i = 0; i < count; i++) {
- if (!sanitize_value_devices (c, base, values))
- return_trace (false);
- values += stride;
- }
-
- return_trace (true);
- }
-
- private:
-
- void should_drop (Value value, Flags flag, unsigned int* format) const
- {
- if (value) return;
- *format = *format & ~flag;
- }
-
-};
-
-template<typename Iterator, typename SrcLookup>
-static void SinglePos_serialize (hb_serialize_context_t *c,
- const SrcLookup *src,
- Iterator it,
- const hb_map_t *layout_variation_idx_map);
-
-
-struct AnchorFormat1
-{
- void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
- float *x, float *y) const
- {
- hb_font_t *font = c->font;
- *x = font->em_fscale_x (xCoordinate);
- *y = font->em_fscale_y (yCoordinate);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this));
- }
-
- AnchorFormat1* copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- AnchorFormat1* out = c->embed<AnchorFormat1> (this);
- if (!out) return_trace (out);
- out->format = 1;
- return_trace (out);
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- FWORD xCoordinate; /* Horizontal value--in design units */
- FWORD yCoordinate; /* Vertical value--in design units */
- public:
- DEFINE_SIZE_STATIC (6);
-};
-
-struct AnchorFormat2
-{
- void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
- float *x, float *y) const
- {
- hb_font_t *font = c->font;
-
-#ifdef HB_NO_HINTING
- *x = font->em_fscale_x (xCoordinate);
- *y = font->em_fscale_y (yCoordinate);
- return;
-#endif
-
- unsigned int x_ppem = font->x_ppem;
- unsigned int y_ppem = font->y_ppem;
- hb_position_t cx = 0, cy = 0;
- bool ret;
-
- ret = (x_ppem || y_ppem) &&
- font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
- *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
- *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this));
- }
-
- AnchorFormat2* copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- return_trace (c->embed<AnchorFormat2> (this));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 2 */
- FWORD xCoordinate; /* Horizontal value--in design units */
- FWORD yCoordinate; /* Vertical value--in design units */
- HBUINT16 anchorPoint; /* Index to glyph contour point */
- public:
- DEFINE_SIZE_STATIC (8);
-};
-
-struct AnchorFormat3
-{
- void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
- float *x, float *y) const
- {
- hb_font_t *font = c->font;
- *x = font->em_fscale_x (xCoordinate);
- *y = font->em_fscale_y (yCoordinate);
-
- if (font->x_ppem || font->num_coords)
- *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
- if (font->y_ppem || font->num_coords)
- *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
- }
-
- AnchorFormat3* copy (hb_serialize_context_t *c,
- const hb_map_t *layout_variation_idx_map) const
- {
- TRACE_SERIALIZE (this);
- if (!layout_variation_idx_map) return_trace (nullptr);
-
- auto *out = c->embed<AnchorFormat3> (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
- out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
- return_trace (out);
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
- (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 3 */
- FWORD xCoordinate; /* Horizontal value--in design units */
- FWORD yCoordinate; /* Vertical value--in design units */
- Offset16To<Device>
- xDeviceTable; /* Offset to Device table for X
- * coordinate-- from beginning of
- * Anchor table (may be NULL) */
- Offset16To<Device>
- yDeviceTable; /* Offset to Device table for Y
- * coordinate-- from beginning of
- * Anchor table (may be NULL) */
- public:
- DEFINE_SIZE_STATIC (10);
-};
-
-struct Anchor
-{
- void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
- float *x, float *y) const
- {
- *x = *y = 0;
- switch (u.format) {
- case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
- case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
- case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
- default: return;
- }
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return_trace (false);
- switch (u.format) {
- case 1: return_trace (u.format1.sanitize (c));
- case 2: return_trace (u.format2.sanitize (c));
- case 3: return_trace (u.format3.sanitize (c));
- default:return_trace (true);
- }
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- switch (u.format) {
- case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
- case 2:
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- {
- // AnchorFormat 2 just containins extra hinting information, so
- // if hints are being dropped convert to format 1.
- return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
- }
- return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
- case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
- c->plan->layout_variation_idx_map))));
- default:return_trace (false);
- }
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- switch (u.format) {
- case 1: case 2:
- return;
- case 3:
- u.format3.collect_variation_indices (c);
- return;
- default: return;
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- AnchorFormat1 format1;
- AnchorFormat2 format2;
- AnchorFormat3 format3;
- } u;
- public:
- DEFINE_SIZE_UNION (2, format);
-};
-
-
-struct AnchorMatrix
-{
- const Anchor& get_anchor (unsigned int row, unsigned int col,
- unsigned int cols, bool *found) const
- {
- *found = false;
- if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
- *found = !matrixZ[row * cols + col].is_null ();
- return this+matrixZ[row * cols + col];
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- Iterator index_iter) const
- {
- for (unsigned i : index_iter)
- (this+matrixZ[i]).collect_variation_indices (c);
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool subset (hb_subset_context_t *c,
- unsigned num_rows,
- Iterator index_iter) const
- {
- TRACE_SUBSET (this);
-
- auto *out = c->serializer->start_embed (this);
-
- if (!index_iter) return_trace (false);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- out->rows = num_rows;
- for (const unsigned i : index_iter)
- {
- auto *offset = c->serializer->embed (matrixZ[i]);
- if (!offset) return_trace (false);
- offset->serialize_subset (c, matrixZ[i], this);
- }
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
- {
- TRACE_SANITIZE (this);
- if (!c->check_struct (this)) return_trace (false);
- if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
- unsigned int count = rows * cols;
- if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
- for (unsigned int i = 0; i < count; i++)
- if (!matrixZ[i].sanitize (c, this)) return_trace (false);
- return_trace (true);
- }
-
- HBUINT16 rows; /* Number of rows */
- UnsizedArrayOf<Offset16To<Anchor>>
- matrixZ; /* Matrix of offsets to Anchor tables--
- * from beginning of AnchorMatrix table */
- public:
- DEFINE_SIZE_ARRAY (2, matrixZ);
-};
-
-
-struct MarkRecord
-{
- friend struct MarkArray;
-
- unsigned get_class () const { return (unsigned) klass; }
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
- }
-
- MarkRecord *subset (hb_subset_context_t *c,
- const void *src_base,
- const hb_map_t *klass_mapping) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- out->klass = klass_mapping->get (klass);
- out->markAnchor.serialize_subset (c, markAnchor, src_base);
- return_trace (out);
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *src_base) const
- {
- (src_base+markAnchor).collect_variation_indices (c);
- }
-
- protected:
- HBUINT16 klass; /* Class defined for this mark */
- Offset16To<Anchor>
- markAnchor; /* Offset to Anchor table--from
- * beginning of MarkArray table */
- public:
- DEFINE_SIZE_STATIC (4);
-};
-
-struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */
-{
- bool apply (hb_ot_apply_context_t *c,
- unsigned int mark_index, unsigned int glyph_index,
- const AnchorMatrix &anchors, unsigned int class_count,
- unsigned int glyph_pos) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
- unsigned int mark_class = record.klass;
-
- const Anchor& mark_anchor = this + record.markAnchor;
- bool found;
- const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
- /* If this subtable doesn't have an anchor for this base and this class,
- * return false such that the subsequent subtables have a chance at it. */
- if (unlikely (!found)) return_trace (false);
-
- float mark_x, mark_y, base_x, base_y;
-
- 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);
-
- hb_glyph_position_t &o = buffer->cur_pos();
- o.x_offset = roundf (base_x - mark_x);
- o.y_offset = roundf (base_y - mark_y);
- o.attach_type() = ATTACH_TYPE_MARK;
- o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
- buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-
- buffer->idx++;
- return_trace (true);
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool subset (hb_subset_context_t *c,
- Iterator coverage,
- const hb_map_t *klass_mapping) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
- auto* out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- auto mark_iter =
- + hb_zip (coverage, this->iter ())
- | hb_filter (glyphset, hb_first)
- | hb_map (hb_second)
- ;
-
- unsigned new_length = 0;
- for (const auto& mark_record : mark_iter) {
- if (unlikely (!mark_record.subset (c, this, klass_mapping)))
- return_trace (false);
- new_length++;
- }
-
- if (unlikely (!c->serializer->check_assign (out->len, new_length,
- HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
- return_trace (false);
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (Array16Of<MarkRecord>::sanitize (c, this));
- }
-};
-
-
-/* Lookups */
-
-struct SinglePosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- if (!valueFormat.has_device ()) return;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (c->glyph_set)
- ;
-
- if (!it) return;
- valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- ValueFormat get_value_format () const { return valueFormat; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- valueFormat.apply_value (c, this, values, buffer->cur_pos());
-
- buffer->idx++;
- return_trace (true);
- }
-
- template<typename Iterator,
- typename SrcLookup,
- hb_requires (hb_is_iterator (Iterator))>
- void serialize (hb_serialize_context_t *c,
- const SrcLookup *src,
- Iterator it,
- ValueFormat newFormat,
- const hb_map_t *layout_variation_idx_map)
- {
- if (unlikely (!c->extend_min (this))) return;
- if (unlikely (!c->check_assign (valueFormat,
- newFormat,
- HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
-
- for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
- {
- src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map);
- // Only serialize the first entry in the iterator, the rest are assumed to
- // be the same.
- break;
- }
-
- auto glyphs =
- + it
- | hb_map_retains_sorting (hb_first)
- ;
-
- 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 it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
- ;
-
- bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- coverage.sanitize (c, this) &&
- valueFormat.sanitize_value (c, this, values));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of subtable */
- ValueFormat valueFormat; /* Defines the types of data in the
- * ValueRecord */
- ValueRecord values; /* Defines positioning
- * value(s)--applied to all glyphs in
- * the Coverage table */
- public:
- DEFINE_SIZE_ARRAY (6, values);
-};
-
-struct SinglePosFormat2
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- if (!valueFormat.has_device ()) return;
-
- auto it =
- + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
- | hb_filter (c->glyph_set, hb_first)
- ;
-
- if (!it) return;
-
- unsigned sub_length = valueFormat.get_len ();
- const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
-
- for (unsigned i : + it
- | hb_map (hb_second))
- valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
-
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- ValueFormat get_value_format () const { return valueFormat; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- if (likely (index >= valueCount)) return_trace (false);
-
- valueFormat.apply_value (c, this,
- &values[index * valueFormat.get_len ()],
- buffer->cur_pos());
-
- buffer->idx++;
- return_trace (true);
- }
-
- template<typename Iterator,
- typename SrcLookup,
- hb_requires (hb_is_iterator (Iterator))>
- void serialize (hb_serialize_context_t *c,
- const SrcLookup *src,
- Iterator it,
- ValueFormat newFormat,
- const hb_map_t *layout_variation_idx_map)
- {
- auto out = c->extend_min (this);
- if (unlikely (!out)) return;
- if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
- if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
-
- + it
- | hb_map (hb_second)
- | hb_apply ([&] (hb_array_t<const Value> _)
- { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
- ;
-
- auto glyphs =
- + it
- | hb_map_retains_sorting (hb_first)
- ;
-
- 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;
-
- unsigned sub_length = valueFormat.get_len ();
- auto values_array = values.as_array (valueCount * sub_length);
-
- auto it =
- + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
- | hb_filter (glyphset, hb_first)
- | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
- {
- return hb_pair (glyph_map[_.first],
- values_array.sub_array (_.second * sub_length,
- sub_length));
- })
- ;
-
- bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- coverage.sanitize (c, this) &&
- valueFormat.sanitize_values (c, this, values, valueCount));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 2 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of subtable */
- ValueFormat valueFormat; /* Defines the types of data in the
- * ValueRecord */
- HBUINT16 valueCount; /* Number of ValueRecords */
- ValueRecord values; /* Array of ValueRecords--positioning
- * values applied to glyphs */
- public:
- DEFINE_SIZE_ARRAY (8, values);
-};
-
-struct SinglePos
-{
- template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- unsigned get_format (Iterator glyph_val_iter_pairs)
- {
- hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
-
- for (const auto iter : glyph_val_iter_pairs)
- for (const auto _ : hb_zip (iter.second, first_val_iter))
- if (_.first != _.second)
- return 2;
-
- return 1;
- }
-
-
- template<typename Iterator,
- typename SrcLookup,
- hb_requires (hb_is_iterator (Iterator))>
- void serialize (hb_serialize_context_t *c,
- const SrcLookup* src,
- Iterator glyph_val_iter_pairs,
- const hb_map_t *layout_variation_idx_map)
- {
- if (unlikely (!c->extend_min (u.format))) return;
- unsigned format = 2;
- ValueFormat new_format = src->get_value_format ();
-
- if (glyph_val_iter_pairs)
- {
- format = get_format (glyph_val_iter_pairs);
- new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
- }
-
- u.format = format;
- switch (u.format) {
- case 1: u.format1.serialize (c,
- src,
- glyph_val_iter_pairs,
- new_format,
- layout_variation_idx_map);
- return;
- case 2: u.format2.serialize (c,
- src,
- glyph_val_iter_pairs,
- new_format,
- layout_variation_idx_map);
- return;
- default:return;
- }
- }
-
- 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 */
- SinglePosFormat1 format1;
- SinglePosFormat2 format2;
- } u;
-};
-
-template<typename Iterator, typename SrcLookup>
-static void
-SinglePos_serialize (hb_serialize_context_t *c,
- const SrcLookup *src,
- Iterator it,
- const hb_map_t *layout_variation_idx_map)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
-
-
-struct PairValueRecord
-{
- friend struct PairSet;
-
- int cmp (hb_codepoint_t k) const
- { return secondGlyph.cmp (k); }
-
- struct context_t
- {
- const void *base;
- const ValueFormat *valueFormats;
- const ValueFormat *newFormats;
- unsigned len1; /* valueFormats[0].get_len() */
- const hb_map_t *glyph_map;
- const hb_map_t *layout_variation_idx_map;
- };
-
- bool subset (hb_subset_context_t *c,
- context_t *closure) const
- {
- TRACE_SERIALIZE (this);
- auto *s = c->serializer;
- auto *out = s->start_embed (*this);
- if (unlikely (!s->extend_min (out))) return_trace (false);
-
- out->secondGlyph = (*closure->glyph_map)[secondGlyph];
-
- closure->valueFormats[0].copy_values (s,
- closure->newFormats[0],
- closure->base, &values[0],
- closure->layout_variation_idx_map);
- closure->valueFormats[1].copy_values (s,
- closure->newFormats[1],
- closure->base,
- &values[closure->len1],
- closure->layout_variation_idx_map);
-
- return_trace (true);
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const ValueFormat *valueFormats,
- const void *base) const
- {
- unsigned record1_len = valueFormats[0].get_len ();
- unsigned record2_len = valueFormats[1].get_len ();
- const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
-
- if (valueFormats[0].has_device ())
- valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
-
- if (valueFormats[1].has_device ())
- valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
- }
-
- bool intersects (const hb_set_t& glyphset) const
- {
- return glyphset.has(secondGlyph);
- }
-
- const Value* get_values_1 () const
- {
- return &values[0];
- }
-
- const Value* get_values_2 (ValueFormat format1) const
- {
- return &values[format1.get_len ()];
- }
-
- protected:
- HBGlyphID16 secondGlyph; /* GlyphID of second glyph in the
- * pair--first glyph is listed in the
- * Coverage table */
- ValueRecord values; /* Positioning data for the first glyph
- * followed by for second glyph */
- public:
- DEFINE_SIZE_ARRAY (2, values);
-};
-
-struct PairSet
-{
- friend struct PairPosFormat1;
-
- bool intersects (const hb_set_t *glyphs,
- const ValueFormat *valueFormats) const
- {
- unsigned int len1 = valueFormats[0].get_len ();
- unsigned int len2 = valueFormats[1].get_len ();
- unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
- const PairValueRecord *record = &firstPairValueRecord;
- unsigned int count = len;
- for (unsigned int i = 0; i < count; i++)
- {
- if (glyphs->has (record->secondGlyph))
- return true;
- record = &StructAtOffset<const PairValueRecord> (record, record_size);
- }
- return false;
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c,
- const ValueFormat *valueFormats) const
- {
- unsigned int len1 = valueFormats[0].get_len ();
- unsigned int len2 = valueFormats[1].get_len ();
- unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
- const PairValueRecord *record = &firstPairValueRecord;
- c->input->add_array (&record->secondGlyph, len, record_size);
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const ValueFormat *valueFormats) const
- {
- unsigned len1 = valueFormats[0].get_len ();
- unsigned len2 = valueFormats[1].get_len ();
- unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
-
- const PairValueRecord *record = &firstPairValueRecord;
- unsigned count = len;
- for (unsigned i = 0; i < count; i++)
- {
- if (c->glyph_set->has (record->secondGlyph))
- { record->collect_variation_indices (c, valueFormats, this); }
-
- record = &StructAtOffset<const PairValueRecord> (record, record_size);
- }
- }
-
- bool apply (hb_ot_apply_context_t *c,
- const ValueFormat *valueFormats,
- unsigned int pos) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int len1 = valueFormats[0].get_len ();
- unsigned int len2 = valueFormats[1].get_len ();
- unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
- const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
- &firstPairValueRecord,
- len,
- record_size);
- if (record)
- {
- bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
- bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
- if (applied_first || applied_second)
- buffer->unsafe_to_break (buffer->idx, pos + 1);
- if (len2)
- pos++;
- buffer->idx = pos;
- return_trace (true);
- }
- buffer->unsafe_to_concat (buffer->idx, pos + 1);
- return_trace (false);
- }
-
- bool subset (hb_subset_context_t *c,
- const ValueFormat valueFormats[2],
- const ValueFormat newFormats[2]) const
- {
- TRACE_SUBSET (this);
- auto snap = c->serializer->snapshot ();
-
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->len = 0;
-
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- unsigned len1 = valueFormats[0].get_len ();
- unsigned len2 = valueFormats[1].get_len ();
- unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
- PairValueRecord::context_t context =
- {
- this,
- valueFormats,
- newFormats,
- len1,
- &glyph_map,
- c->plan->layout_variation_idx_map
- };
-
- const PairValueRecord *record = &firstPairValueRecord;
- unsigned count = len, num = 0;
- for (unsigned i = 0; i < count; i++)
- {
- if (glyphset.has (record->secondGlyph)
- && record->subset (c, &context)) num++;
- record = &StructAtOffset<const PairValueRecord> (record, record_size);
- }
-
- out->len = num;
- if (!num) c->serializer->revert (snap);
- return_trace (num);
- }
-
- struct sanitize_closure_t
- {
- const ValueFormat *valueFormats;
- unsigned int len1; /* valueFormats[0].get_len() */
- unsigned int stride; /* 1 + len1 + len2 */
- };
-
- bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
- {
- TRACE_SANITIZE (this);
- if (!(c->check_struct (this)
- && c->check_range (&firstPairValueRecord,
- len,
- HBUINT16::static_size,
- closure->stride))) return_trace (false);
-
- unsigned int count = len;
- const PairValueRecord *record = &firstPairValueRecord;
- return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
- closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
- }
-
- protected:
- HBUINT16 len; /* Number of PairValueRecords */
- PairValueRecord firstPairValueRecord;
- /* Array of PairValueRecords--ordered
- * by GlyphID of the second glyph */
- public:
- DEFINE_SIZE_MIN (2);
-};
-
-struct PairPosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return
- + hb_zip (this+coverage, pairSet)
- | hb_filter (*glyphs, hb_first)
- | hb_map (hb_second)
- | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
- { return (this+_).intersects (glyphs, valueFormat); })
- | hb_any
- ;
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
-
- auto it =
- + hb_zip (this+coverage, pairSet)
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- ;
-
- if (!it) return;
- + it
- | hb_map (hb_add (this))
- | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
- ;
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- unsigned int count = pairSet.len;
- for (unsigned int i = 0; i < count; i++)
- (this+pairSet[i]).collect_glyphs (c, valueFormat);
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
- 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));
- }
-
- 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;
- out->valueFormat[0] = valueFormat[0];
- out->valueFormat[1] = valueFormat[1];
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- {
- hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
- out->valueFormat[0] = newFormats.first;
- out->valueFormat[1] = newFormats.second;
- }
-
- hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-
- + hb_zip (this+coverage, pairSet)
- | hb_filter (glyphset, hb_first)
- | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
- {
- auto snap = c->serializer->snapshot ();
- auto *o = out->pairSet.serialize_append (c->serializer);
- if (unlikely (!o)) return false;
- bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
- if (!ret)
- {
- out->pairSet.pop ();
- c->serializer->revert (snap);
- }
- return ret;
- },
- 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));
- }
-
-
- hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
- {
- unsigned len1 = valueFormat[0].get_len ();
- unsigned len2 = valueFormat[1].get_len ();
- unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
- unsigned format1 = 0;
- unsigned format2 = 0;
- for (const Offset16To<PairSet>& _ :
- + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
- {
- const PairSet& set = (this + _);
- const PairValueRecord *record = &set.firstPairValueRecord;
-
- for (unsigned i = 0; i < set.len; i++)
- {
- if (record->intersects (glyphset))
- {
- format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
- format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
- }
- record = &StructAtOffset<const PairValueRecord> (record, record_size);
- }
- }
-
- return hb_pair (format1, format2);
- }
-
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
-
- if (!c->check_struct (this)) return_trace (false);
-
- unsigned int len1 = valueFormat[0].get_len ();
- unsigned int len2 = valueFormat[1].get_len ();
- PairSet::sanitize_closure_t closure =
- {
- valueFormat,
- len1,
- 1 + len1 + len2
- };
-
- return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of subtable */
- ValueFormat valueFormat[2]; /* [0] Defines the types of data in
- * ValueRecord1--for the first glyph
- * in the pair--may be zero (0) */
- /* [1] Defines the types of data in
- * ValueRecord2--for the second glyph
- * in the pair--may be zero (0) */
- Array16OfOffset16To<PairSet>
- pairSet; /* Array of PairSet tables
- * ordered by Coverage Index */
- public:
- DEFINE_SIZE_ARRAY (10, pairSet);
-};
-
-struct PairPosFormat2
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return (this+coverage).intersects (glyphs) &&
- (this+classDef2).intersects (glyphs);
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- if (!intersects (c->glyph_set)) return;
- if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
-
- hb_set_t klass1_glyphs, klass2_glyphs;
- if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
- if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
-
- hb_set_t class1_set, class2_set;
- for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
- {
- if (!klass1_glyphs.has (cp)) class1_set.add (0);
- else
- {
- unsigned klass1 = (this+classDef1).get (cp);
- class1_set.add (klass1);
- }
- }
-
- class2_set.add (0);
- for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
- {
- unsigned klass2 = (this+classDef2).get (cp);
- class2_set.add (klass2);
- }
-
- if (class1_set.is_empty ()
- || class2_set.is_empty ()
- || (class2_set.get_population() == 1 && class2_set.has(0)))
- return;
-
- unsigned len1 = valueFormat1.get_len ();
- unsigned len2 = valueFormat2.get_len ();
- const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
- for (const unsigned class1_idx : class1_set.iter ())
- {
- for (const unsigned class2_idx : class2_set.iter ())
- {
- unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
- if (valueFormat1.has_device ())
- valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
-
- if (valueFormat2.has_device ())
- valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
- }
- }
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
- 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 ();
- unsigned int record_len = len1 + len2;
-
- 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))
- {
- 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 = 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)
- buffer->idx++;
-
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->format = format;
-
- hb_map_t klass1_map;
- out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
- out->class1Count = klass1_map.get_population ();
-
- hb_map_t klass2_map;
- out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
- out->class2Count = klass2_map.get_population ();
-
- unsigned len1 = valueFormat1.get_len ();
- unsigned len2 = valueFormat2.get_len ();
-
- hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- newFormats = compute_effective_value_formats (klass1_map, klass2_map);
-
- out->valueFormat1 = newFormats.first;
- out->valueFormat2 = newFormats.second;
-
- for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
- {
- for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
- {
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
- valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
- valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
- }
- }
-
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- out->coverage.serialize_serialize (c->serializer, it);
- return_trace (out->class1Count && out->class2Count && bool (it));
- }
-
-
- hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
- const hb_map_t& klass2_map) const
- {
- unsigned len1 = valueFormat1.get_len ();
- unsigned len2 = valueFormat2.get_len ();
-
- unsigned format1 = 0;
- unsigned format2 = 0;
-
- for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
- {
- for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
- {
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
- format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
- format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
- }
- }
-
- return hb_pair (format1, format2);
- }
-
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (!(c->check_struct (this)
- && coverage.sanitize (c, this)
- && classDef1.sanitize (c, this)
- && classDef2.sanitize (c, this))) return_trace (false);
-
- unsigned int len1 = valueFormat1.get_len ();
- unsigned int len2 = valueFormat2.get_len ();
- unsigned int stride = len1 + len2;
- unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
- unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
- return_trace (c->check_range ((const void *) values,
- count,
- record_size) &&
- valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
- valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 2 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of subtable */
- ValueFormat valueFormat1; /* ValueRecord definition--for the
- * first glyph of the pair--may be zero
- * (0) */
- ValueFormat valueFormat2; /* ValueRecord definition--for the
- * second glyph of the pair--may be
- * zero (0) */
- Offset16To<ClassDef>
- classDef1; /* Offset to ClassDef table--from
- * beginning of PairPos subtable--for
- * the first glyph of the pair */
- Offset16To<ClassDef>
- classDef2; /* Offset to ClassDef table--from
- * beginning of PairPos subtable--for
- * the second glyph of the pair */
- HBUINT16 class1Count; /* Number of classes in ClassDef1
- * table--includes Class0 */
- HBUINT16 class2Count; /* Number of classes in ClassDef2
- * table--includes Class0 */
- ValueRecord values; /* Matrix of value pairs:
- * class1-major, class2-minor,
- * Each entry has value1 and value2 */
- public:
- DEFINE_SIZE_ARRAY (16, values);
-};
-
-struct PairPos
-{
- 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 */
- PairPosFormat1 format1;
- PairPosFormat2 format2;
- } u;
-};
-
-
-struct EntryExitRecord
-{
- friend struct CursivePosFormat1;
-
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
- {
- TRACE_SANITIZE (this);
- return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
- }
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *src_base) const
- {
- (src_base+entryAnchor).collect_variation_indices (c);
- (src_base+exitAnchor).collect_variation_indices (c);
- }
-
- EntryExitRecord* subset (hb_subset_context_t *c,
- const void *src_base) const
- {
- TRACE_SERIALIZE (this);
- auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
- out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
- return_trace (out);
- }
-
- protected:
- Offset16To<Anchor>
- entryAnchor; /* Offset to EntryAnchor table--from
- * beginning of CursivePos
- * subtable--may be NULL */
- Offset16To<Anchor>
- exitAnchor; /* Offset to ExitAnchor table--from
- * beginning of CursivePos
- * subtable--may be NULL */
- public:
- DEFINE_SIZE_STATIC (4);
-};
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
-
-struct CursivePosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- + hb_zip (this+coverage, entryExitRecord)
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
- ;
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
-
- const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
- if (!this_record.entryAnchor) return_trace (false);
-
- hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
- 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)
- {
- 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;
-
- buffer->unsafe_to_break (i, j);
- float entry_x, entry_y, exit_x, exit_y;
- (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
- (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
-
- hb_glyph_position_t *pos = buffer->pos;
-
- hb_position_t d;
- /* Main-direction adjustment */
- switch (c->direction) {
- case HB_DIRECTION_LTR:
- pos[i].x_advance = roundf (exit_x) + pos[i].x_offset;
-
- d = roundf (entry_x) + pos[j].x_offset;
- pos[j].x_advance -= d;
- pos[j].x_offset -= d;
- break;
- case HB_DIRECTION_RTL:
- d = roundf (exit_x) + pos[i].x_offset;
- pos[i].x_advance -= d;
- pos[i].x_offset -= d;
-
- pos[j].x_advance = roundf (entry_x) + pos[j].x_offset;
- break;
- case HB_DIRECTION_TTB:
- pos[i].y_advance = roundf (exit_y) + pos[i].y_offset;
-
- d = roundf (entry_y) + pos[j].y_offset;
- pos[j].y_advance -= d;
- pos[j].y_offset -= d;
- break;
- case HB_DIRECTION_BTT:
- d = roundf (exit_y) + pos[i].y_offset;
- pos[i].y_advance -= d;
- pos[i].y_offset -= d;
-
- pos[j].y_advance = roundf (entry_y);
- break;
- case HB_DIRECTION_INVALID:
- default:
- break;
- }
-
- /* Cross-direction adjustment */
-
- /* We attach child to parent (think graph theory and rooted trees whereas
- * the root stays on baseline and each node aligns itself against its
- * parent.
- *
- * Optimize things for the case of RightToLeft, as that's most common in
- * Arabic. */
- unsigned int child = i;
- unsigned int parent = j;
- hb_position_t x_offset = entry_x - exit_x;
- hb_position_t y_offset = entry_y - exit_y;
- if (!(c->lookup_props & LookupFlag::RightToLeft))
- {
- unsigned int k = child;
- child = parent;
- parent = k;
- x_offset = -x_offset;
- y_offset = -y_offset;
- }
-
- /* If child was already connected to someone else, walk through its old
- * chain and reverse the link direction, such that the whole tree of its
- * previous connection now attaches to new parent. Watch out for case
- * where new parent is on the path from old chain...
- */
- reverse_cursive_minor_offset (pos, child, c->direction, parent);
-
- pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
- pos[child].attach_chain() = (int) parent - (int) child;
- buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
- if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
- pos[child].y_offset = y_offset;
- else
- pos[child].x_offset = x_offset;
-
- /* If parent was attached to child, separate them.
- * https://github.com/harfbuzz/harfbuzz/issues/2469
- */
- if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
- pos[parent].attach_chain() = 0;
-
- buffer->idx++;
- return_trace (true);
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- void serialize (hb_subset_context_t *c,
- Iterator it,
- const void *src_base)
- {
- if (unlikely (!c->serializer->extend_min ((*this)))) return;
- this->format = 1;
- this->entryExitRecord.len = it.len ();
-
- for (const EntryExitRecord& entry_record : + it
- | hb_map (hb_second))
- entry_record.subset (c, src_base);
-
- auto glyphs =
- + it
- | hb_map_retains_sorting (hb_first)
- ;
-
- coverage.serialize_serialize (c->serializer, 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 (!out)) return_trace (false);
-
- auto it =
- + hb_zip (this+coverage, entryExitRecord)
- | hb_filter (glyphset, hb_first)
- | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
- { return hb_pair (glyph_map[p.first], p.second);})
- ;
-
- bool ret = bool (it);
- out->serialize (c, it, this);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of subtable */
- Array16Of<EntryExitRecord>
- entryExitRecord; /* Array of EntryExit records--in
- * Coverage Index order */
- public:
- DEFINE_SIZE_ARRAY (6, entryExitRecord);
-};
-
-struct CursivePos
-{
- 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 */
- CursivePosFormat1 format1;
- } u;
-};
-
-
-typedef AnchorMatrix BaseArray; /* base-major--
- * in order of BaseCoverage Index--,
- * mark-minor--
- * ordered by class--zero-based. */
-
-static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
- const MarkArray &mark_array,
- const hb_set_t &glyphset,
- hb_map_t* klass_mapping /* INOUT */)
-{
- hb_set_t orig_classes;
-
- + hb_zip (mark_coverage, mark_array)
- | hb_filter (glyphset, hb_first)
- | hb_map (hb_second)
- | hb_map (&MarkRecord::get_class)
- | hb_sink (orig_classes)
- ;
-
- unsigned idx = 0;
- for (auto klass : orig_classes.iter ())
- {
- if (klass_mapping->has (klass)) continue;
- klass_mapping->set (klass, idx);
- idx++;
- }
-}
-
-struct MarkBasePosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return (this+markCoverage).intersects (glyphs) &&
- (this+baseCoverage).intersects (glyphs);
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- + hb_zip (this+markCoverage, this+markArray)
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
- ;
-
- hb_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
- unsigned basecount = (this+baseArray).rows;
- auto base_iter =
- + hb_zip (this+baseCoverage, hb_range (basecount))
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- ;
-
- hb_sorted_vector_t<unsigned> base_indexes;
- for (const unsigned row : base_iter)
- {
- + hb_range ((unsigned) classCount)
- | hb_filter (klass_mapping)
- | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
- | hb_sink (base_indexes)
- ;
- }
- (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
- if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
- }
-
- const Coverage &get_coverage () const { return this+markCoverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
- if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
- /* Now we search backwards for a non-mark glyph */
- 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);
- do {
- 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...
- * ...but stop if we find a mark in the MultipleSubst sequence:
- * https://github.com/harfbuzz/harfbuzz/issues/1020 */
- if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
- 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
- (skippy_iter.idx == 0 ||
- _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
- _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
- _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
- _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
- _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
- ))
- break;
- skippy_iter.reject ();
- } while (true);
-
- /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
- //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)
- {
- 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));
- }
-
- 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_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
- if (!klass_mapping.get_population ()) return_trace (false);
- out->classCount = klass_mapping.get_population ();
-
- auto mark_iter =
- + hb_zip (this+markCoverage, this+markArray)
- | hb_filter (glyphset, hb_first)
- ;
-
- hb_sorted_vector_t<hb_codepoint_t> new_coverage;
- + mark_iter
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
-
- if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
- return_trace (false);
-
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
-
- unsigned basecount = (this+baseArray).rows;
- auto base_iter =
- + hb_zip (this+baseCoverage, hb_range (basecount))
- | hb_filter (glyphset, hb_first)
- ;
-
- new_coverage.reset ();
- + base_iter
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
-
- if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
- return_trace (false);
-
- hb_sorted_vector_t<unsigned> base_indexes;
- for (const unsigned row : + base_iter
- | hb_map (hb_second))
- {
- + hb_range ((unsigned) classCount)
- | hb_filter (klass_mapping)
- | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
- | hb_sink (base_indexes)
- ;
- }
-
- out->baseArray.serialize_subset (c, baseArray, this,
- base_iter.len (),
- base_indexes.iter ());
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- markCoverage.sanitize (c, this) &&
- baseCoverage.sanitize (c, this) &&
- markArray.sanitize (c, this) &&
- baseArray.sanitize (c, this, (unsigned int) classCount));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- markCoverage; /* Offset to MarkCoverage table--from
- * beginning of MarkBasePos subtable */
- Offset16To<Coverage>
- baseCoverage; /* Offset to BaseCoverage table--from
- * beginning of MarkBasePos subtable */
- HBUINT16 classCount; /* Number of classes defined for marks */
- Offset16To<MarkArray>
- markArray; /* Offset to MarkArray table--from
- * beginning of MarkBasePos subtable */
- Offset16To<BaseArray>
- baseArray; /* Offset to BaseArray table--from
- * beginning of MarkBasePos subtable */
- public:
- DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkBasePos
-{
- 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 */
- MarkBasePosFormat1 format1;
- } u;
-};
-
-
-typedef AnchorMatrix LigatureAttach; /* component-major--
- * in order of writing direction--,
- * mark-minor--
- * ordered by class--zero-based. */
-
-/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : List16OfOffset16To<LigatureAttach>
-{
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool subset (hb_subset_context_t *c,
- Iterator coverage,
- unsigned class_count,
- const hb_map_t *klass_mapping) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- for (const auto _ : + hb_zip (coverage, *this)
- | hb_filter (glyphset, hb_first))
- {
- auto *matrix = out->serialize_append (c->serializer);
- if (unlikely (!matrix)) return_trace (false);
-
- const LigatureAttach& src = (this + _.second);
- auto indexes =
- + hb_range (src.rows * class_count)
- | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
- ;
- matrix->serialize_subset (c,
- _.second,
- this,
- src.rows,
- indexes);
- }
- return_trace (this->len);
- }
-};
-
-struct MarkLigPosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return (this+markCoverage).intersects (glyphs) &&
- (this+ligatureCoverage).intersects (glyphs);
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- + hb_zip (this+markCoverage, this+markArray)
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
- ;
-
- hb_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
- unsigned ligcount = (this+ligatureArray).len;
- auto lig_iter =
- + hb_zip (this+ligatureCoverage, hb_range (ligcount))
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- ;
-
- const LigatureArray& lig_array = this+ligatureArray;
- for (const unsigned i : lig_iter)
- {
- hb_sorted_vector_t<unsigned> lig_indexes;
- unsigned row_count = lig_array[i].rows;
- for (unsigned row : + hb_range (row_count))
- {
- + hb_range ((unsigned) classCount)
- | hb_filter (klass_mapping)
- | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
- | hb_sink (lig_indexes)
- ;
- }
-
- lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
- }
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
- if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
- }
-
- const Coverage &get_coverage () const { return this+markCoverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
- if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
- /* Now we search backwards for a non-mark glyph */
- 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);
- 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)
- {
- 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))
- {
- 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
- * can directly use the component index. If not, we attach the mark
- * glyph to the last component of the ligature. */
- unsigned int comp_index;
- unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
- unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
- unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
- if (lig_id && lig_id == mark_id && mark_comp > 0)
- comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
- else
- comp_index = comp_count - 1;
-
- return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
- }
-
- 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_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
- if (!klass_mapping.get_population ()) return_trace (false);
- out->classCount = klass_mapping.get_population ();
-
- auto mark_iter =
- + hb_zip (this+markCoverage, this+markArray)
- | hb_filter (glyphset, hb_first)
- ;
-
- auto new_mark_coverage =
- + mark_iter
- | hb_map_retains_sorting (hb_first)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
- return_trace (false);
-
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
-
- auto new_ligature_coverage =
- + hb_iter (this + ligatureCoverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
- return_trace (false);
-
- out->ligatureArray.serialize_subset (c, ligatureArray, this,
- hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- markCoverage.sanitize (c, this) &&
- ligatureCoverage.sanitize (c, this) &&
- markArray.sanitize (c, this) &&
- ligatureArray.sanitize (c, this, (unsigned int) classCount));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- markCoverage; /* Offset to Mark Coverage table--from
- * beginning of MarkLigPos subtable */
- Offset16To<Coverage>
- ligatureCoverage; /* Offset to Ligature Coverage
- * table--from beginning of MarkLigPos
- * subtable */
- HBUINT16 classCount; /* Number of defined mark classes */
- Offset16To<MarkArray>
- markArray; /* Offset to MarkArray table--from
- * beginning of MarkLigPos subtable */
- Offset16To<LigatureArray>
- ligatureArray; /* Offset to LigatureArray table--from
- * beginning of MarkLigPos subtable */
- public:
- DEFINE_SIZE_STATIC (12);
-};
-
-
-struct MarkLigPos
-{
- 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 */
- MarkLigPosFormat1 format1;
- } u;
-};
-
-
-typedef AnchorMatrix Mark2Array; /* mark2-major--
- * in order of Mark2Coverage Index--,
- * mark1-minor--
- * ordered by class--zero-based. */
-
-struct MarkMarkPosFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return (this+mark1Coverage).intersects (glyphs) &&
- (this+mark2Coverage).intersects (glyphs);
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- + hb_zip (this+mark1Coverage, this+mark1Array)
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
- ;
-
- hb_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
-
- unsigned mark2_count = (this+mark2Array).rows;
- auto mark2_iter =
- + hb_zip (this+mark2Coverage, hb_range (mark2_count))
- | hb_filter (c->glyph_set, hb_first)
- | hb_map (hb_second)
- ;
-
- hb_sorted_vector_t<unsigned> mark2_indexes;
- for (const unsigned row : mark2_iter)
- {
- + hb_range ((unsigned) classCount)
- | hb_filter (klass_mapping)
- | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
- | hb_sink (mark2_indexes)
- ;
- }
- (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
- if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
- }
-
- const Coverage &get_coverage () const { return this+mark1Coverage; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_buffer_t *buffer = c->buffer;
- unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
- if (likely (mark1_index == NOT_COVERED)) return_trace (false);
-
- /* now we search backwards for a suitable mark glyph until a non-mark glyph */
- 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);
- 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]))
- {
- buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
- return_trace (false);
- }
-
- unsigned int j = skippy_iter.idx;
-
- unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
- unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
- unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
- unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
-
- if (likely (id1 == id2))
- {
- if (id1 == 0) /* Marks belonging to the same base. */
- goto good;
- else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
- goto good;
- }
- else
- {
- /* If ligature ids don't match, it may be the case that one of the marks
- * itself is a ligature. In which case match. */
- if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
- goto good;
- }
-
- /* 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)
- {
- 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));
- }
-
- 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_map_t klass_mapping;
- Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
-
- if (!klass_mapping.get_population ()) return_trace (false);
- out->classCount = klass_mapping.get_population ();
-
- auto mark1_iter =
- + hb_zip (this+mark1Coverage, this+mark1Array)
- | hb_filter (glyphset, hb_first)
- ;
-
- hb_sorted_vector_t<hb_codepoint_t> new_coverage;
- + mark1_iter
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
-
- if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
- return_trace (false);
-
- out->mark1Array.serialize_subset (c, mark1Array, this,
- (this+mark1Coverage).iter (),
- &klass_mapping);
-
- unsigned mark2count = (this+mark2Array).rows;
- auto mark2_iter =
- + hb_zip (this+mark2Coverage, hb_range (mark2count))
- | hb_filter (glyphset, hb_first)
- ;
-
- new_coverage.reset ();
- + mark2_iter
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
-
- if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
- return_trace (false);
-
- hb_sorted_vector_t<unsigned> mark2_indexes;
- for (const unsigned row : + mark2_iter
- | hb_map (hb_second))
- {
- + hb_range ((unsigned) classCount)
- | hb_filter (klass_mapping)
- | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
- | hb_sink (mark2_indexes)
- ;
- }
-
- out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- mark1Coverage.sanitize (c, this) &&
- mark2Coverage.sanitize (c, this) &&
- mark1Array.sanitize (c, this) &&
- mark2Array.sanitize (c, this, (unsigned int) classCount));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- mark1Coverage; /* Offset to Combining Mark1 Coverage
- * table--from beginning of MarkMarkPos
- * subtable */
- Offset16To<Coverage>
- mark2Coverage; /* Offset to Combining Mark2 Coverage
- * table--from beginning of MarkMarkPos
- * subtable */
- HBUINT16 classCount; /* Number of defined mark classes */
- Offset16To<MarkArray>
- mark1Array; /* Offset to Mark1Array table--from
- * beginning of MarkMarkPos subtable */
- Offset16To<Mark2Array>
- mark2Array; /* Offset to Mark2Array table--from
- * beginning of MarkMarkPos subtable */
- public:
- DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkMarkPos
-{
- 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 */
- MarkMarkPosFormat1 format1;
- } u;
-};
-
-
-struct ContextPos : Context {};
-
-struct ChainContextPos : ChainContext {};
-
-struct ExtensionPos : Extension<ExtensionPos>
-{
- typedef struct PosLookupSubTable SubTable;
-};
-
-
-
-/*
- * PosLookup
- */
-
-
-struct PosLookupSubTable
-{
- friend struct Lookup;
- friend struct PosLookup;
-
- enum Type {
- Single = 1,
- Pair = 2,
- Cursive = 3,
- MarkBase = 4,
- MarkLig = 5,
- MarkMark = 6,
- Context = 7,
- ChainContext = 8,
- Extension = 9
- };
-
- 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 Pair: return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
- case Cursive: return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
- case MarkBase: return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
- case MarkLig: return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
- case MarkMark: return_trace (u.markMark.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)...));
- 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 {
- SinglePos single;
- PairPos pair;
- CursivePos cursive;
- MarkBasePos markBase;
- MarkLigPos markLig;
- MarkMarkPos markMark;
- ContextPos context;
- ChainContextPos chainContext;
- ExtensionPos extension;
- } u;
- public:
- DEFINE_SIZE_MIN (0);
-};
-
-
-struct PosLookup : Lookup
-{
- typedef struct PosLookupSubTable SubTable;
-
- const SubTable& get_subtable (unsigned int i) const
- { return Lookup::get_subtable<SubTable> (i); }
-
- bool is_reverse () const
- {
- return false;
- }
-
- 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_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
- { return dispatch (c); }
-
- 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;
- }
-
- template <typename set_t>
- void collect_coverage (set_t *glyphs) const
- {
- hb_collect_coverage_context_t<set_t> c (glyphs);
- dispatch (&c);
- }
-
- static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
- template <typename context_t>
- static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
- HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_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); }
-};
-
-/*
- * GPOS -- Glyph Positioning
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
- */
-
-struct GPOS : GSUBGPOS
-{
- static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
-
- const PosLookup& get_lookup (unsigned int i) const
- { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
-
- static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
- static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
- static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
-
- bool subset (hb_subset_context_t *c) const
- {
- hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
- return GSUBGPOS::subset<PosLookup> (&l);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- { return GSUBGPOS::sanitize<PosLookup> (c); }
-
- HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
- hb_face_t *face) const;
-
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- {
- for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
- {
- if (!c->gpos_lookups->has (i)) continue;
- const PosLookup &l = get_lookup (i);
- l.dispatch (c);
- }
- }
-
- void closure_lookups (hb_face_t *face,
- const hb_set_t *glyphs,
- hb_set_t *lookup_indexes /* IN/OUT */) const
- { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
-
- typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
-};
-
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
-{
- int chain = pos[i].attach_chain(), type = pos[i].attach_type();
- if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
- return;
-
- pos[i].attach_chain() = 0;
-
- unsigned int j = (int) i + chain;
-
- /* Stop if we see new parent in the chain. */
- if (j == new_parent)
- return;
-
- reverse_cursive_minor_offset (pos, j, direction, new_parent);
-
- if (HB_DIRECTION_IS_HORIZONTAL (direction))
- pos[j].y_offset = -pos[i].y_offset;
- else
- pos[j].x_offset = -pos[i].x_offset;
-
- pos[j].attach_chain() = -chain;
- pos[j].attach_type() = type;
-}
-static void
-propagate_attachment_offsets (hb_glyph_position_t *pos,
- unsigned int len,
- unsigned int i,
- hb_direction_t direction)
-{
- /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
- * offset of glyph they are attached to. */
- int chain = pos[i].attach_chain(), type = pos[i].attach_type();
- if (likely (!chain))
- return;
-
- pos[i].attach_chain() = 0;
-
- unsigned int j = (int) i + chain;
-
- if (unlikely (j >= len))
- return;
-
- propagate_attachment_offsets (pos, len, j, direction);
-
- assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
-
- if (type & ATTACH_TYPE_CURSIVE)
- {
- if (HB_DIRECTION_IS_HORIZONTAL (direction))
- pos[i].y_offset += pos[j].y_offset;
- else
- pos[i].x_offset += pos[j].x_offset;
- }
- else /*if (type & ATTACH_TYPE_MARK)*/
- {
- pos[i].x_offset += pos[j].x_offset;
- pos[i].y_offset += pos[j].y_offset;
-
- assert (j < i);
- if (HB_DIRECTION_IS_FORWARD (direction))
- for (unsigned int k = j; k < i; k++) {
- pos[i].x_offset -= pos[k].x_advance;
- pos[i].y_offset -= pos[k].y_advance;
- }
- else
- for (unsigned int k = j + 1; k < i + 1; k++) {
- pos[i].x_offset += pos[k].x_advance;
- pos[i].y_offset += pos[k].y_advance;
- }
- }
-}
-
-void
-GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
-{
- unsigned int count = buffer->len;
- for (unsigned int i = 0; i < count; i++)
- buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
-}
-
-void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
- //_hb_buffer_assert_gsubgpos_vars (buffer);
-}
-
-void
-GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
-{
- _hb_buffer_assert_gsubgpos_vars (buffer);
-
- unsigned int len;
- hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
- hb_direction_t direction = buffer->props.direction;
-
- /* Handle attachments */
- if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
- 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 {
- GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {}
-};
-
+using Layout::GPOS_impl::PosLookup;
+// TODO(garretrieger): Move into new layout directory.
/* Out-of-class implementation for methods recursing */
-
#ifndef HB_NO_OT_LAYOUT
template <typename context_t>
/*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
@@ -3121,13 +45,16 @@ template <typename context_t>
return l.dispatch (c);
}
-/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+template <>
+inline hb_closure_lookups_context_t::return_t
+PosLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index)
{
const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index);
return l.closure_lookups (c, this_index);
}
-/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+template <>
+inline bool PosLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index)
{
const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
@@ -3141,7 +68,6 @@ template <typename context_t>
}
#endif
-
} /* namespace OT */
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
index bef381430b..462542025b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -59,13 +59,16 @@ template <typename context_t>
return l.dispatch (c);
}
-/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+template <>
+inline hb_closure_lookups_context_t::return_t
+SubstLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
return l.closure_lookups (c, this_index);
}
-/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+template <>
+inline bool SubstLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index 3faa1e53d5..31da498652 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -109,14 +109,10 @@ struct hb_closure_context_t :
{
done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
- if (!done_lookups_glyph_set->get (lookup_index))
+ if (!done_lookups_glyph_set->has (lookup_index))
{
- hb_set_t* empty_set = hb_set_create ();
- if (unlikely (!done_lookups_glyph_set->set (lookup_index, empty_set)))
- {
- hb_set_destroy (empty_set);
+ if (unlikely (!done_lookups_glyph_set->set (lookup_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
return true;
- }
}
hb_set_clear (done_lookups_glyph_set->get (lookup_index));
@@ -165,21 +161,19 @@ struct hb_closure_context_t :
hb_set_t *glyphs;
hb_set_t output[1];
hb_vector_t<hb_set_t> active_glyphs_stack;
- recurse_func_t recurse_func;
+ recurse_func_t recurse_func = nullptr;
unsigned int nesting_level_left;
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
hb_map_t *done_lookups_glyph_count_,
- hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_,
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set_,
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
glyphs (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)
+ done_lookups_glyph_set (done_lookups_glyph_set_)
{}
~hb_closure_context_t () { flush (); }
@@ -197,8 +191,8 @@ struct hb_closure_context_t :
private:
hb_map_t *done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set;
- unsigned int lookup_count;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set;
+ unsigned int lookup_count = 0;
};
@@ -400,7 +394,6 @@ struct hb_collect_coverage_context_t :
set_t *set;
};
-
struct hb_ot_apply_context_t :
hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
{
@@ -416,7 +409,7 @@ struct hb_ot_apply_context_t :
match_func (nullptr),
match_data (nullptr) {}
- typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
+ typedef bool (*match_func_t) (hb_glyph_info_t &info, const HBUINT16 &value, const void *data);
void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
@@ -434,7 +427,7 @@ struct hb_ot_apply_context_t :
MATCH_MAYBE
};
- may_match_t may_match (const hb_glyph_info_t &info,
+ may_match_t may_match (hb_glyph_info_t &info,
const HBUINT16 *glyph_data) const
{
if (!(info.mask & mask) ||
@@ -442,7 +435,7 @@ struct hb_ot_apply_context_t :
return MATCH_NO;
if (match_func)
- return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+ return match_func (info, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
return MATCH_MAYBE;
}
@@ -530,7 +523,7 @@ struct hb_ot_apply_context_t :
while (idx + num_items < end)
{
idx++;
- const hb_glyph_info_t &info = c->buffer->info[idx];
+ hb_glyph_info_t &info = c->buffer->info[idx];
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
if (unlikely (skip == matcher_t::SKIP_YES))
@@ -563,7 +556,7 @@ struct hb_ot_apply_context_t :
while (idx > num_items - 1)
{
idx--;
- const hb_glyph_info_t &info = c->buffer->out_info[idx];
+ hb_glyph_info_t &info = c->buffer->out_info[idx];
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
if (unlikely (skip == matcher_t::SKIP_YES))
@@ -611,7 +604,10 @@ struct hb_ot_apply_context_t :
return_t recurse (unsigned int sub_lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
+ {
+ buffer->shaping_failed = true;
return default_return_value ();
+ }
nesting_level_left--;
bool ret = recurse_func (this, sub_lookup_index);
@@ -621,35 +617,34 @@ struct hb_ot_apply_context_t :
skipping_iterator_t iter_input, iter_context;
+ unsigned int table_index; /* GSUB/GPOS */
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
- recurse_func_t recurse_func;
+ recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const VariationStore &var_store;
+ VariationStore::cache_t *var_store_cache;
hb_direction_t direction;
- hb_mask_t lookup_mask;
- unsigned int table_index; /* GSUB/GPOS */
- unsigned int lookup_index;
- unsigned int lookup_props;
- unsigned int nesting_level_left;
+ hb_mask_t lookup_mask = 1;
+ unsigned int lookup_index = (unsigned) -1;
+ unsigned int lookup_props = 0;
+ unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL;
bool has_glyph_classes;
- bool auto_zwnj;
- bool auto_zwj;
- bool per_syllable;
- bool random;
-
- uint32_t random_state;
-
+ bool auto_zwnj = true;
+ bool auto_zwj = true;
+ bool per_syllable = false;
+ bool random = false;
+ uint32_t random_state = 1;
+ unsigned new_syllables = (unsigned) -1;
hb_ot_apply_context_t (unsigned int table_index_,
hb_font_t *font_,
hb_buffer_t *buffer_) :
- iter_input (), iter_context (),
+ table_index (table_index_),
font (font_), face (font->face), buffer (buffer_),
- recurse_func (nullptr),
gdef (
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF->table
@@ -658,18 +653,23 @@ struct hb_ot_apply_context_t :
#endif
),
var_store (gdef.get_var_store ()),
+ var_store_cache (
+#ifndef HB_NO_VAR
+ table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr
+#else
+ nullptr
+#endif
+ ),
direction (buffer_->props.direction),
- lookup_mask (1),
- table_index (table_index_),
- lookup_index ((unsigned int) -1),
- lookup_props (0),
- nesting_level_left (HB_MAX_NESTING_LEVEL),
- has_glyph_classes (gdef.has_glyph_classes ()),
- auto_zwnj (true),
- auto_zwj (true),
- per_syllable (false),
- random (false),
- random_state (1) { init_iters (); }
+ has_glyph_classes (gdef.has_glyph_classes ())
+ { init_iters (); }
+
+ ~hb_ot_apply_context_t ()
+ {
+#ifndef HB_NO_VAR
+ VariationStore::destroy_cache (var_store_cache);
+#endif
+ }
void init_iters ()
{
@@ -736,6 +736,9 @@ struct hb_ot_apply_context_t :
bool ligature = false,
bool component = false) const
{
+ if (new_syllables != (unsigned) -1)
+ buffer->cur().syllable() = new_syllables;
+
unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
if (ligature)
@@ -790,8 +793,8 @@ struct hb_ot_apply_context_t :
};
-struct hb_get_subtables_context_t :
- hb_dispatch_context_t<hb_get_subtables_context_t>
+struct hb_accelerate_subtables_context_t :
+ hb_dispatch_context_t<hb_accelerate_subtables_context_t>
{
template <typename Type>
static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
@@ -800,15 +803,53 @@ struct hb_get_subtables_context_t :
return typed_obj->apply (c);
}
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ template <typename T>
+ static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
+ template <typename T>
+ static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
+ template <typename Type>
+ static inline bool apply_cached_to (const void *obj, OT::hb_ot_apply_context_t *c)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return apply_cached_ (typed_obj, c, hb_prioritize);
+ }
+
+ template <typename T>
+ static inline auto cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
+ template <typename T>
+ static inline bool cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
+ template <typename Type>
+ static inline bool cache_func_to (const void *obj, OT::hb_ot_apply_context_t *c, bool enter)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return cache_func_ (typed_obj, c, enter, hb_prioritize);
+ }
+#endif
+
typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
+ typedef bool (*hb_cache_func_t) (const void *obj, OT::hb_ot_apply_context_t *c, bool enter);
struct hb_applicable_t
{
+ friend struct hb_accelerate_subtables_context_t;
+ friend struct hb_ot_layout_lookup_accelerator_t;
+
template <typename T>
- void init (const T &obj_, hb_apply_func_t apply_func_)
+ void init (const T &obj_,
+ hb_apply_func_t apply_func_
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ , hb_apply_func_t apply_cached_func_
+ , hb_cache_func_t cache_func_
+#endif
+ )
{
obj = &obj_;
apply_func = apply_func_;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ apply_cached_func = apply_cached_func_;
+ cache_func = cache_func_;
+#endif
digest.init ();
obj_.get_coverage ().collect_coverage (&digest);
}
@@ -817,38 +858,93 @@ struct hb_get_subtables_context_t :
{
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
}
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ bool apply_cached (OT::hb_ot_apply_context_t *c) const
+ {
+ return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
+ }
+ bool cache_enter (OT::hb_ot_apply_context_t *c) const
+ {
+ return cache_func (obj, c, true);
+ }
+ void cache_leave (OT::hb_ot_apply_context_t *c) const
+ {
+ cache_func (obj, c, false);
+ }
+#endif
private:
const void *obj;
hb_apply_func_t apply_func;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ hb_apply_func_t apply_cached_func;
+ hb_cache_func_t cache_func;
+#endif
hb_set_digest_t digest;
};
typedef hb_vector_t<hb_applicable_t> array_t;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ template <typename T>
+ auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
+ template <typename T>
+ auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
+#endif
+
/* Dispatch interface. */
template <typename T>
return_t dispatch (const T &obj)
{
- hb_applicable_t *entry = array.push();
- entry->init (obj, apply_to<T>);
+ hb_applicable_t entry;
+
+ entry.init (obj,
+ apply_to<T>
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ , apply_cached_to<T>
+ , cache_func_to<T>
+#endif
+ );
+
+ array.push (entry);
+
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ /* Cache handling
+ *
+ * We allow one subtable from each lookup to use a cache. The assumption
+ * being that multiple subtables of the same lookup cannot use a cache
+ * because the resources they would use will collide. As such, we ask
+ * each subtable to tell us how much it costs (which a cache would avoid),
+ * and we allocate the cache opportunity to the costliest subtable.
+ */
+ unsigned cost = cache_cost (obj, hb_prioritize);
+ if (cost > cache_user_cost && !array.in_error ())
+ {
+ cache_user_idx = array.length - 1;
+ cache_user_cost = cost;
+ }
+#endif
+
return hb_empty_t ();
}
static return_t default_return_value () { return hb_empty_t (); }
- hb_get_subtables_context_t (array_t &array_) :
- array (array_) {}
+ hb_accelerate_subtables_context_t (array_t &array_) :
+ array (array_) {}
array_t &array;
-};
-
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ unsigned cache_user_idx = (unsigned) -1;
+ unsigned cache_user_cost = 0;
+#endif
+};
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
-typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
+typedef bool (*match_func_t) (hb_glyph_info_t &info, const HBUINT16 &value, const void *data);
struct ContextClosureFuncs
{
@@ -863,6 +959,10 @@ struct ContextApplyFuncs
{
match_func_t match;
};
+struct ChainContextApplyFuncs
+{
+ match_func_t match[3];
+};
static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
@@ -939,19 +1039,30 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
}
-static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_glyph_info_t &info, const HBUINT16 &value, const void *data HB_UNUSED)
{
- return glyph_id == value;
+ return info.codepoint == value;
}
-static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
+static inline bool match_class (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- return class_def.get_class (glyph_id) == value;
+ return class_def.get_class (info.codepoint) == value;
}
-static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
+static inline bool match_class_cached (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
+{
+ unsigned klass = info.syllable();
+ if (klass < 255)
+ return klass == value;
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ klass = class_def.get_class (info.codepoint);
+ if (likely (klass < 255))
+ info.syllable() = klass;
+ return klass == value;
+}
+static inline bool match_coverage (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
{
const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
- return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
+ return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
}
static inline bool would_match_input (hb_would_apply_context_t *c,
@@ -964,8 +1075,12 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
return false;
for (unsigned int i = 1; i < count; i++)
- if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
+ {
+ hb_glyph_info_t info;
+ info.codepoint = c->glyphs[i];
+ if (likely (!match_func (info, input[i - 1], match_data)))
return false;
+ }
return true;
}
@@ -1328,7 +1443,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
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))
{
has_pos_glyphs = true;
if (seqIndex == 0)
@@ -1361,7 +1476,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
covered_seq_indicies->add (seqIndex);
if (has_pos_glyphs) {
- c->push_cur_active_glyphs () = pos_glyphs;
+ c->push_cur_active_glyphs () = std::move (pos_glyphs);
} else {
c->push_cur_active_glyphs ().set (*c->glyphs);
}
@@ -1415,11 +1530,6 @@ static inline void 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))
- continue;
-
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
/* This can happen if earlier recursed lookups deleted many entries. */
@@ -1457,11 +1567,10 @@ static inline void 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.
*/
@@ -2131,19 +2240,54 @@ struct ContextFormat2
const Coverage &get_coverage () const { return this+coverage; }
- bool apply (hb_ot_apply_context_t *c) const
+ unsigned cache_cost () const
+ {
+ unsigned c = (this+classDef).cost () * ruleSet.len;
+ return c >= 4 ? c : 0;
+ }
+ bool cache_func (hb_ot_apply_context_t *c, bool enter) const
+ {
+ if (enter)
+ {
+ if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
+ return false;
+ auto &info = c->buffer->info;
+ unsigned count = c->buffer->len;
+ for (unsigned i = 0; i < count; i++)
+ info[i].syllable() = 255;
+ c->new_syllables = 255;
+ return true;
+ }
+ else
+ {
+ c->new_syllables = (unsigned) -1;
+ HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
+ return true;
+ }
+ }
+
+ bool apply (hb_ot_apply_context_t *c, bool cached = false) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const ClassDef &class_def = this+classDef;
- index = class_def.get_class (c->buffer->cur().codepoint);
- const RuleSet &rule_set = this+ruleSet[index];
+
struct ContextApplyLookupContext lookup_context = {
- {match_class},
+ {cached ? match_class_cached : match_class},
&class_def
};
+
+ if (cached && c->buffer->cur().syllable() < 255)
+ index = c->buffer->cur().syllable ();
+ else
+ {
+ index = class_def.get_class (c->buffer->cur().codepoint);
+ if (cached && index < 255)
+ c->buffer->cur().syllable() = index;
+ }
+ const RuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@@ -2417,7 +2561,7 @@ struct ChainContextCollectGlyphsLookupContext
struct ChainContextApplyLookupContext
{
- ContextApplyFuncs funcs;
+ ChainContextApplyFuncs funcs;
const void *match_data[3];
};
@@ -2505,7 +2649,7 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
&& would_match_input (c,
inputCount, input,
- lookup_context.funcs.match, lookup_context.match_data[1]);
+ lookup_context.funcs.match[1], lookup_context.match_data[1]);
}
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
@@ -2524,11 +2668,11 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
if (!(match_input (c,
inputCount, input,
- lookup_context.funcs.match, lookup_context.match_data[1],
+ lookup_context.funcs.match[1], 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],
+ lookup_context.funcs.match[2], lookup_context.match_data[2],
match_end, &end_index)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
@@ -2538,7 +2682,7 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
unsigned start_index = c->buffer->out_len;
if (!match_backtrack (c,
backtrackCount, backtrack,
- lookup_context.funcs.match, lookup_context.match_data[0],
+ lookup_context.funcs.match[0], lookup_context.match_data[0],
&start_index))
{
c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
@@ -2940,7 +3084,7 @@ struct ChainContextFormat1
{
const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
struct ChainContextApplyLookupContext lookup_context = {
- {match_glyph},
+ {{match_glyph, match_glyph, match_glyph}},
{nullptr, nullptr, nullptr}
};
return rule_set.would_apply (c, lookup_context);
@@ -2956,7 +3100,7 @@ struct ChainContextFormat1
const ChainRuleSet &rule_set = this+ruleSet[index];
struct ChainContextApplyLookupContext lookup_context = {
- {match_glyph},
+ {{match_glyph, match_glyph, match_glyph}},
{nullptr, nullptr, nullptr}
};
return_trace (rule_set.apply (c, lookup_context));
@@ -3140,7 +3284,7 @@ struct ChainContextFormat2
unsigned int index = input_class_def.get_class (c->glyphs[0]);
const ChainRuleSet &rule_set = this+ruleSet[index];
struct ChainContextApplyLookupContext lookup_context = {
- {match_class},
+ {{match_class, match_class, match_class}},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -3150,7 +3294,33 @@ struct ChainContextFormat2
const Coverage &get_coverage () const { return this+coverage; }
- bool apply (hb_ot_apply_context_t *c) const
+ unsigned cache_cost () const
+ {
+ unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len;
+ return c >= 4 ? c : 0;
+ }
+ bool cache_func (hb_ot_apply_context_t *c, bool enter) const
+ {
+ if (enter)
+ {
+ if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
+ return false;
+ auto &info = c->buffer->info;
+ unsigned count = c->buffer->len;
+ for (unsigned i = 0; i < count; i++)
+ info[i].syllable() = 255;
+ c->new_syllables = 255;
+ return true;
+ }
+ else
+ {
+ c->new_syllables = (unsigned) -1;
+ HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
+ return true;
+ }
+ }
+
+ bool apply (hb_ot_apply_context_t *c, bool cached = false) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -3160,14 +3330,27 @@ struct ChainContextFormat2
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
- index = input_class_def.get_class (c->buffer->cur().codepoint);
- const ChainRuleSet &rule_set = this+ruleSet[index];
+ /* For ChainContextFormat2 we cache the LookaheadClassDef instead of InputClassDef.
+ * The reason is that most heavy fonts want to identify a glyph in context and apply
+ * a lookup to it. In this scenario, the length of the input sequence is one, whereas
+ * the lookahead / backtrack are typically longer. The one glyph in input sequence is
+ * looked-up below and no input glyph is looked up in individual rules, whereas the
+ * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack,
+ * we should cache lookahead. This decisions showed a 20% improvement in shaping of
+ * the Gulzar font.
+ */
+
struct ChainContextApplyLookupContext lookup_context = {
- {match_class},
+ {{cached && &backtrack_class_def == &input_class_def ? match_class_cached : match_class,
+ cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class,
+ cached ? match_class_cached : match_class}},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
};
+
+ index = input_class_def.get_class (c->buffer->cur().codepoint);
+ const ChainRuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@@ -3365,7 +3548,7 @@ struct ChainContextFormat3
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
- {match_coverage},
+ {{match_coverage, match_coverage, match_coverage}},
{this, this, this}
};
return chain_context_would_apply_lookup (c,
@@ -3392,7 +3575,7 @@ struct ChainContextFormat3
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
- {match_coverage},
+ {{match_coverage, match_coverage, match_coverage}},
{this, this, this}
};
return_trace (chain_context_apply_lookup (c,
@@ -3629,25 +3812,63 @@ struct hb_ot_layout_lookup_accelerator_t
lookup.collect_coverage (&digest);
subtables.init ();
- OT::hb_get_subtables_context_t c_get_subtables (subtables);
- lookup.dispatch (&c_get_subtables);
+ OT::hb_accelerate_subtables_context_t c_accelerate_subtables (subtables);
+ lookup.dispatch (&c_accelerate_subtables);
+
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ cache_user_idx = c_accelerate_subtables.cache_user_idx;
+ for (unsigned i = 0; i < subtables.length; i++)
+ if (i != cache_user_idx)
+ subtables[i].apply_cached_func = subtables[i].apply_func;
+#endif
}
void fini () { subtables.fini (); }
bool may_have (hb_codepoint_t g) const
{ return digest.may_have (g); }
- bool apply (hb_ot_apply_context_t *c) const
+ bool apply (hb_ot_apply_context_t *c, bool use_cache) const
{
- for (unsigned int i = 0; i < subtables.length; i++)
- if (subtables[i].apply (c))
- return true;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ if (use_cache)
+ {
+ for (unsigned int i = 0; i < subtables.length; i++)
+ if (subtables[i].apply_cached (c))
+ return true;
+ }
+ else
+#endif
+ {
+ for (unsigned int i = 0; i < subtables.length; i++)
+ if (subtables[i].apply (c))
+ return true;
+ }
return false;
}
+ bool cache_enter (OT::hb_ot_apply_context_t *c) const
+ {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ return cache_user_idx != (unsigned) -1 &&
+ subtables[cache_user_idx].cache_enter (c);
+#else
+ return false;
+#endif
+ }
+ void cache_leave (OT::hb_ot_apply_context_t *c) const
+ {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ subtables[cache_user_idx].cache_leave (c);
+#endif
+ }
+
+
private:
hb_set_digest_t digest;
- hb_get_subtables_context_t::array_t subtables;
+ hb_accelerate_subtables_context_t::array_t subtables;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ unsigned cache_user_idx = (unsigned) -1;
+#endif
};
struct GSUBGPOS
@@ -3727,6 +3948,8 @@ struct GSUBGPOS
hb_set_t visited_lookups, inactive_lookups;
OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
+ c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
+
for (unsigned lookup_index : + hb_iter (lookup_indexes))
reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
@@ -3735,7 +3958,7 @@ struct GSUBGPOS
}
void prune_langsys (const hb_map_t *duplicate_feature_map,
- hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map,
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
hb_set_t *new_feature_indexes /* OUT */) const
{
hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
@@ -3793,7 +4016,7 @@ struct GSUBGPOS
hb_map_t *duplicate_feature_map /* OUT */) const
{
if (feature_indices->is_empty ()) return;
- hb_hashmap_t<hb_tag_t, hb_set_t *> unique_features;
+ hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
//find out duplicate features after subset
for (unsigned i : feature_indices->iter ())
{
@@ -3801,16 +4024,9 @@ struct GSUBGPOS
if (t == HB_MAP_VALUE_INVALID) continue;
if (!unique_features.has (t))
{
- hb_set_t* indices = hb_set_create ();
- if (unlikely (indices == hb_set_get_empty () ||
- !unique_features.set (t, indices)))
- {
- hb_set_destroy (indices);
- for (auto _ : unique_features.iter ())
- hb_set_destroy (_.second);
+ if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
return;
- }
- if (unique_features.get (t))
+ if (unique_features.has (t))
unique_features.get (t)->add (i);
duplicate_feature_map->set (i, i);
continue;
@@ -3855,9 +4071,6 @@ struct GSUBGPOS
duplicate_feature_map->set (i, i);
}
}
-
- for (auto _ : unique_features.iter ())
- hb_set_destroy (_.second);
}
void prune_features (const hb_map_t *lookup_indices, /* IN */
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index f4ea21a4f9..142c843dad 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -46,7 +46,7 @@
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-name-table.hh"
#include "hb-ot-os2-table.hh"
@@ -55,6 +55,7 @@
#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
/**
* SECTION:hb-ot-layout
@@ -260,7 +261,6 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
{
_hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
_hb_glyph_info_clear_lig_props (&buffer->info[i]);
- buffer->info[i].syllable() = 0;
}
}
@@ -401,7 +401,7 @@ GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
}
bool
-OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
hb_face_t *face HB_UNUSED) const
{
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -1501,15 +1501,12 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
hb_set_t *glyphs /* OUT */)
{
hb_map_t done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> 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);
l.closure (&c, lookup_index);
-
- for (auto _ : done_lookups_glyph_set.iter ())
- hb_set_destroy (_.second);
}
/**
@@ -1529,7 +1526,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
hb_set_t *glyphs /* OUT */)
{
hb_map_t done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set;
OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
const GSUB& gsub = *face->table.GSUB->table;
@@ -1551,13 +1548,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
}
} while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
glyphs_length != glyphs->get_population ());
-
- for (auto _ : done_lookups_glyph_set.iter ())
- hb_set_destroy (_.second);
}
/*
- * OT::GPOS
+ * GPOS
*/
@@ -1588,7 +1582,7 @@ hb_ot_layout_has_positioning (hb_face_t *face)
void
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_start (font, buffer);
+ GPOS::position_start (font, buffer);
}
@@ -1603,7 +1597,7 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
void
hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_finish_advances (font, buffer);
+ GPOS::position_finish_advances (font, buffer);
}
/**
@@ -1617,7 +1611,7 @@ hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
void
hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_finish_offsets (font, buffer);
+ GPOS::position_finish_offsets (font, buffer);
}
@@ -1652,7 +1646,7 @@ hb_ot_layout_get_size_params (hb_face_t *face,
unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */)
{
- const OT::GPOS &gpos = *face->table.GPOS->table;
+ const GPOS &gpos = *face->table.GPOS->table;
const hb_tag_t tag = HB_TAG ('s','i','z','e');
unsigned int num_features = gpos.get_feature_count ();
@@ -1803,7 +1797,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
struct GSUBProxy
{
static constexpr unsigned table_index = 0u;
- static constexpr bool inplace = false;
+ static constexpr bool always_inplace = false;
typedef OT::SubstLookup Lookup;
GSUBProxy (hb_face_t *face) :
@@ -1817,14 +1811,14 @@ struct GSUBProxy
struct GPOSProxy
{
static constexpr unsigned table_index = 1u;
- static constexpr bool inplace = true;
+ static constexpr bool always_inplace = true;
typedef OT::PosLookup Lookup;
GPOSProxy (hb_face_t *face) :
table (*face->table.GPOS->table),
accels (face->table.GPOS->accels) {}
- const OT::GPOS &table;
+ const GPOS &table;
const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
@@ -1833,6 +1827,8 @@ static inline bool
apply_forward (OT::hb_ot_apply_context_t *c,
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
+ bool use_cache = accel.cache_enter (c);
+
bool ret = false;
hb_buffer_t *buffer = c->buffer;
while (buffer->idx < buffer->len && buffer->successful)
@@ -1842,7 +1838,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
- applied = accel.apply (c);
+ applied = accel.apply (c, use_cache);
}
if (applied)
@@ -1850,6 +1846,10 @@ apply_forward (OT::hb_ot_apply_context_t *c,
else
(void) buffer->next_glyph ();
}
+
+ if (use_cache)
+ accel.cache_leave (c);
+
return ret;
}
@@ -1864,7 +1864,7 @@ apply_backward (OT::hb_ot_apply_context_t *c,
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
- ret |= accel.apply (c);
+ ret |= accel.apply (c, false);
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -1890,13 +1890,13 @@ apply_string (OT::hb_ot_apply_context_t *c,
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
- if (!Proxy::inplace)
+ if (!Proxy::always_inplace)
buffer->clear_output ();
buffer->idx = 0;
apply_forward (c, accel);
- if (!Proxy::inplace)
+ if (!Proxy::always_inplace)
buffer->sync ();
}
else
@@ -1917,7 +1917,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
const unsigned int table_index = proxy.table_index;
unsigned int i = 0;
OT::hb_ot_apply_context_t c (table_index, font, buffer);
- c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+ c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);
for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh
index 75bba0bc50..6395f06670 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh
@@ -589,13 +589,11 @@ _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
- HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
}
static inline void
_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
{
- HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
}
@@ -605,7 +603,6 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
HB_BUFFER_ASSERT_VAR (buffer, lig_props);
- HB_BUFFER_ASSERT_VAR (buffer, syllable);
}
/* Make sure no one directly touches our props... */
diff --git a/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh b/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh
index c496dc2981..0e0f2d632a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh
@@ -45,7 +45,7 @@ struct hb_ot_language_map_t
};
static const hb_ot_language_map_t
-hb_ms_language_map[] =
+_hb_ms_language_map[] =
{
{0x0001, "ar"}, /* ??? */
{0x0004, "zh"}, /* ??? */
@@ -298,7 +298,7 @@ hb_ms_language_map[] =
};
static const hb_ot_language_map_t
-hb_mac_language_map[] =
+_hb_mac_language_map[] =
{
{ 0, "en"}, /* English */
{ 1, "fr"}, /* French */
@@ -441,16 +441,16 @@ hb_language_t
_hb_ot_name_language_for_ms_code (unsigned int code)
{
return _hb_ot_name_language_for (code,
- hb_ms_language_map,
- ARRAY_LENGTH (hb_ms_language_map));
+ _hb_ms_language_map,
+ ARRAY_LENGTH (_hb_ms_language_map));
}
hb_language_t
_hb_ot_name_language_for_mac_code (unsigned int code)
{
return _hb_ot_name_language_for (code,
- hb_mac_language_map,
- ARRAY_LENGTH (hb_mac_language_map));
+ _hb_mac_language_map,
+ ARRAY_LENGTH (_hb_mac_language_map));
}
#endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-name-table.hh b/thirdparty/harfbuzz/src/hb-ot-name-table.hh
index d52367e9b1..01107aad67 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-name-table.hh
@@ -156,7 +156,7 @@ struct NameRecord
};
static int
-_hb_ot_name_entry_cmp_key (const void *pa, const void *pb)
+_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
{
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
@@ -169,8 +169,23 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb)
if (a->language == b->language) return 0;
if (!a->language) return -1;
if (!b->language) return +1;
- return strcmp (hb_language_to_string (a->language),
- hb_language_to_string (b->language));
+
+ const char *astr = hb_language_to_string (a->language);
+ const char *bstr = hb_language_to_string (b->language);
+
+ signed c = strcmp (astr, bstr);
+
+ if (!exact && c)
+ {
+ unsigned la = strlen (astr);
+ unsigned lb = strlen (bstr);
+ // 'a' is the user request, and 'b' is string in the font.
+ // If eg. user asks for "en-us" and font has "en", approve.
+ if (la > lb && astr[lb] == '-' && !strncmp (astr, bstr, lb))
+ return 0;
+ }
+
+ return c;
}
static int
@@ -178,7 +193,7 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb)
{
/* Compare by name_id, then language, then score, then index. */
- int v = _hb_ot_name_entry_cmp_key (pa, pb);
+ int v = _hb_ot_name_entry_cmp_key (pa, pb, true);
if (v)
return v;
@@ -330,7 +345,18 @@ struct name
const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
this->names.length,
sizeof (hb_ot_name_entry_t),
- _hb_ot_name_entry_cmp_key);
+ _hb_ot_name_entry_cmp_key,
+ true);
+
+ if (!entry)
+ {
+ entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
+ this->names.length,
+ sizeof (hb_ot_name_entry_t),
+ _hb_ot_name_entry_cmp_key,
+ false);
+ }
+
if (!entry)
return -1;
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index f0035e2f04..3473afef54 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -224,9 +224,11 @@ struct OS2
*max_cp = hb_min (0xFFFFu, codepoints->get_max ());
}
- /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */
+ /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
+ * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */
enum font_page_t
{
+ FONT_PAGE_NONE = 0,
FONT_PAGE_HEBREW = 0xB100, /* Hebrew Windows 3.1 font page */
FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */
FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
index 0f3cd8e24f..4d427e5431 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
@@ -52,16 +52,16 @@ HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
{
unsigned glyph_id = _.first;
unsigned new_index = _.second;
-
+
if (new_index < 258) continue;
if (copied_indices.has (new_index)) continue;
copied_indices.add (new_index);
-
+
hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id);
HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1));
if (unlikely (!o)) return_trace (false);
if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
- memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
+ hb_memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
}
return_trace (true);
@@ -78,17 +78,19 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
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;
+ hb_hashmap_t<hb_bytes_t, unsigned, true> glyph_name_to_new_index;
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
unsigned old_index = glyphNameIndex[old_gid];
unsigned new_index;
+ const unsigned *new_index2;
if (old_index <= 257) new_index = old_index;
- else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
- else
+ else if (old_new_index_map.has (old_index, &new_index2))
{
+ new_index = *new_index2;
+ } else {
hb_bytes_t s = _post.find_glyph_name (old_gid);
new_index = glyph_name_to_new_index.get (s);
if (new_index == (unsigned)-1)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
deleted file mode 100644
index 74bf3ca0fa..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ /dev/null
@@ -1,603 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-indic-machine.rl"
-/*
- * Copyright © 2011,2012 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-
-#include "hb.hh"
-
-enum indic_syllable_type_t {
- indic_consonant_syllable,
- indic_vowel_syllable,
- indic_standalone_cluster,
- indic_symbol_cluster,
- indic_broken_cluster,
- indic_non_indic_cluster,
-};
-
-
-#line 45 "hb-ot-shape-complex-indic-machine.hh"
-#define indic_syllable_machine_ex_A 10u
-#define indic_syllable_machine_ex_C 1u
-#define indic_syllable_machine_ex_CM 17u
-#define indic_syllable_machine_ex_CS 19u
-#define indic_syllable_machine_ex_DOTTEDCIRCLE 12u
-#define indic_syllable_machine_ex_H 4u
-#define indic_syllable_machine_ex_M 7u
-#define indic_syllable_machine_ex_N 3u
-#define indic_syllable_machine_ex_PLACEHOLDER 11u
-#define indic_syllable_machine_ex_RS 13u
-#define indic_syllable_machine_ex_Ra 16u
-#define indic_syllable_machine_ex_Repha 15u
-#define indic_syllable_machine_ex_SM 8u
-#define indic_syllable_machine_ex_Symbol 18u
-#define indic_syllable_machine_ex_V 2u
-#define indic_syllable_machine_ex_ZWJ 6u
-#define indic_syllable_machine_ex_ZWNJ 5u
-
-
-#line 65 "hb-ot-shape-complex-indic-machine.hh"
-static const unsigned char _indic_syllable_machine_trans_keys[] = {
- 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
- 4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u,
- 4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u,
- 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u,
- 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u,
- 3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
- 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u,
- 5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u,
- 4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u,
- 3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
- 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u,
- 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u,
- 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u,
- 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0
-};
-
-static const char _indic_syllable_machine_key_spans[] = {
- 1, 5, 3, 4, 5, 1, 1, 5,
- 10, 5, 1, 3, 4, 5, 1, 1,
- 5, 10, 10, 10, 1, 3, 4, 5,
- 1, 1, 5, 5, 10, 1, 3, 4,
- 5, 1, 1, 5, 5, 4, 1, 19,
- 15, 15, 14, 16, 6, 6, 1, 6,
- 16, 16, 16, 8, 7, 6, 7, 6,
- 8, 6, 15, 15, 15, 15, 14, 16,
- 15, 15, 14, 16, 6, 1, 6, 16,
- 16, 8, 7, 6, 7, 6, 6, 8,
- 6, 15, 15, 5, 15, 15, 14, 16,
- 15, 16, 6, 1, 6, 16, 16, 8,
- 7, 6, 15, 7, 6, 6, 8, 6,
- 15, 10, 5, 15, 15, 14, 16, 15,
- 16, 6, 1, 6, 16, 16, 8, 7,
- 6, 15, 7, 6, 6, 8, 6, 17,
- 15, 17, 10, 6, 1, 6, 16, 8,
- 6, 6, 1, 6, 16
-};
-
-static const short _indic_syllable_machine_index_offsets[] = {
- 0, 2, 8, 12, 17, 23, 25, 27,
- 33, 44, 50, 52, 56, 61, 67, 69,
- 71, 77, 88, 99, 110, 112, 116, 121,
- 127, 129, 131, 137, 143, 154, 156, 160,
- 165, 171, 173, 175, 181, 187, 192, 194,
- 214, 230, 246, 261, 278, 285, 292, 294,
- 301, 318, 335, 352, 361, 369, 376, 384,
- 391, 400, 407, 423, 439, 455, 471, 486,
- 503, 519, 535, 550, 567, 574, 576, 583,
- 600, 617, 626, 634, 641, 649, 656, 663,
- 672, 679, 695, 711, 717, 733, 749, 764,
- 781, 797, 814, 821, 823, 830, 847, 864,
- 873, 881, 888, 904, 912, 919, 926, 935,
- 942, 958, 969, 975, 991, 1007, 1022, 1039,
- 1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131,
- 1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200,
- 1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296,
- 1305, 1312, 1319, 1321, 1328
-};
-
-static const unsigned char _indic_syllable_machine_indicies[] = {
- 1, 0, 2, 3, 3, 4, 1, 0,
- 3, 3, 4, 0, 3, 3, 4, 1,
- 0, 5, 3, 3, 4, 1, 0, 6,
- 0, 7, 0, 8, 3, 3, 4, 1,
- 0, 2, 3, 3, 4, 1, 0, 0,
- 0, 0, 9, 0, 11, 12, 12, 13,
- 14, 10, 14, 10, 12, 12, 13, 10,
- 12, 12, 13, 14, 10, 15, 12, 12,
- 13, 14, 10, 16, 10, 17, 10, 18,
- 12, 12, 13, 14, 10, 11, 12, 12,
- 13, 14, 10, 10, 10, 10, 19, 10,
- 11, 12, 12, 13, 14, 10, 10, 10,
- 10, 20, 10, 22, 23, 23, 24, 25,
- 21, 21, 21, 21, 26, 21, 25, 21,
- 23, 23, 24, 27, 23, 23, 24, 25,
- 21, 28, 23, 23, 24, 25, 21, 29,
- 21, 30, 21, 22, 23, 23, 24, 25,
- 21, 31, 23, 23, 24, 25, 21, 33,
- 34, 34, 35, 36, 32, 32, 32, 32,
- 37, 32, 36, 32, 34, 34, 35, 32,
- 34, 34, 35, 36, 32, 38, 34, 34,
- 35, 36, 32, 39, 32, 40, 32, 33,
- 34, 34, 35, 36, 32, 41, 34, 34,
- 35, 36, 32, 23, 23, 24, 1, 0,
- 43, 42, 45, 46, 47, 48, 49, 50,
- 24, 25, 44, 51, 52, 52, 26, 44,
- 53, 54, 55, 56, 57, 44, 59, 60,
- 61, 62, 4, 1, 58, 63, 58, 58,
- 9, 58, 58, 58, 64, 58, 65, 60,
- 66, 66, 4, 1, 58, 63, 58, 58,
- 58, 58, 58, 58, 64, 58, 60, 66,
- 66, 4, 1, 58, 63, 58, 58, 58,
- 58, 58, 58, 64, 58, 45, 58, 58,
- 58, 67, 68, 58, 1, 58, 63, 58,
- 58, 58, 58, 58, 45, 58, 69, 69,
- 58, 1, 58, 63, 58, 63, 58, 58,
- 70, 58, 63, 58, 63, 58, 63, 58,
- 58, 58, 58, 63, 58, 45, 58, 71,
- 58, 69, 69, 58, 1, 58, 63, 58,
- 58, 58, 58, 58, 45, 58, 45, 58,
- 58, 58, 69, 69, 58, 1, 58, 63,
- 58, 58, 58, 58, 58, 45, 58, 45,
- 58, 58, 58, 69, 68, 58, 1, 58,
- 63, 58, 58, 58, 58, 58, 45, 58,
- 72, 7, 73, 74, 4, 1, 58, 63,
- 58, 7, 73, 74, 4, 1, 58, 63,
- 58, 73, 73, 4, 1, 58, 63, 58,
- 75, 76, 76, 4, 1, 58, 63, 58,
- 67, 77, 58, 1, 58, 63, 58, 67,
- 58, 69, 69, 58, 1, 58, 63, 58,
- 69, 77, 58, 1, 58, 63, 58, 59,
- 60, 66, 66, 4, 1, 58, 63, 58,
- 58, 58, 58, 58, 58, 64, 58, 59,
- 60, 61, 66, 4, 1, 58, 63, 58,
- 58, 9, 58, 58, 58, 64, 58, 79,
- 80, 81, 82, 13, 14, 78, 83, 78,
- 78, 20, 78, 78, 78, 84, 78, 85,
- 80, 86, 82, 13, 14, 78, 83, 78,
- 78, 78, 78, 78, 78, 84, 78, 80,
- 86, 82, 13, 14, 78, 83, 78, 78,
- 78, 78, 78, 78, 84, 78, 87, 78,
- 78, 78, 88, 89, 78, 14, 78, 83,
- 78, 78, 78, 78, 78, 87, 78, 90,
- 80, 91, 92, 13, 14, 78, 83, 78,
- 78, 19, 78, 78, 78, 84, 78, 93,
- 80, 86, 86, 13, 14, 78, 83, 78,
- 78, 78, 78, 78, 78, 84, 78, 80,
- 86, 86, 13, 14, 78, 83, 78, 78,
- 78, 78, 78, 78, 84, 78, 87, 78,
- 78, 78, 94, 89, 78, 14, 78, 83,
- 78, 78, 78, 78, 78, 87, 78, 83,
- 78, 78, 95, 78, 83, 78, 83, 78,
- 83, 78, 78, 78, 78, 83, 78, 87,
- 78, 96, 78, 94, 94, 78, 14, 78,
- 83, 78, 78, 78, 78, 78, 87, 78,
- 87, 78, 78, 78, 94, 94, 78, 14,
- 78, 83, 78, 78, 78, 78, 78, 87,
- 78, 97, 17, 98, 99, 13, 14, 78,
- 83, 78, 17, 98, 99, 13, 14, 78,
- 83, 78, 98, 98, 13, 14, 78, 83,
- 78, 100, 101, 101, 13, 14, 78, 83,
- 78, 88, 102, 78, 14, 78, 83, 78,
- 94, 94, 78, 14, 78, 83, 78, 88,
- 78, 94, 94, 78, 14, 78, 83, 78,
- 94, 102, 78, 14, 78, 83, 78, 90,
- 80, 86, 86, 13, 14, 78, 83, 78,
- 78, 78, 78, 78, 78, 84, 78, 90,
- 80, 91, 86, 13, 14, 78, 83, 78,
- 78, 19, 78, 78, 78, 84, 78, 11,
- 12, 12, 13, 14, 78, 79, 80, 86,
- 82, 13, 14, 78, 83, 78, 78, 78,
- 78, 78, 78, 84, 78, 104, 48, 105,
- 105, 24, 25, 103, 51, 103, 103, 103,
- 103, 103, 103, 55, 103, 48, 105, 105,
- 24, 25, 103, 51, 103, 103, 103, 103,
- 103, 103, 55, 103, 106, 103, 103, 103,
- 107, 108, 103, 25, 103, 51, 103, 103,
- 103, 103, 103, 106, 103, 47, 48, 109,
- 110, 24, 25, 103, 51, 103, 103, 26,
- 103, 103, 103, 55, 103, 106, 103, 103,
- 103, 111, 108, 103, 25, 103, 51, 103,
- 103, 103, 103, 103, 106, 103, 51, 103,
- 103, 112, 103, 51, 103, 51, 103, 51,
- 103, 103, 103, 103, 51, 103, 106, 103,
- 113, 103, 111, 111, 103, 25, 103, 51,
- 103, 103, 103, 103, 103, 106, 103, 106,
- 103, 103, 103, 111, 111, 103, 25, 103,
- 51, 103, 103, 103, 103, 103, 106, 103,
- 114, 30, 115, 116, 24, 25, 103, 51,
- 103, 30, 115, 116, 24, 25, 103, 51,
- 103, 115, 115, 24, 25, 103, 51, 103,
- 47, 48, 105, 105, 24, 25, 103, 51,
- 103, 103, 103, 103, 103, 103, 55, 103,
- 117, 118, 118, 24, 25, 103, 51, 103,
- 107, 119, 103, 25, 103, 51, 103, 111,
- 111, 103, 25, 103, 51, 103, 107, 103,
- 111, 111, 103, 25, 103, 51, 103, 111,
- 119, 103, 25, 103, 51, 103, 47, 48,
- 109, 105, 24, 25, 103, 51, 103, 103,
- 26, 103, 103, 103, 55, 103, 22, 23,
- 23, 24, 25, 120, 120, 120, 120, 26,
- 120, 22, 23, 23, 24, 25, 120, 122,
- 123, 124, 125, 35, 36, 121, 126, 121,
- 121, 37, 121, 121, 121, 127, 121, 128,
- 123, 125, 125, 35, 36, 121, 126, 121,
- 121, 121, 121, 121, 121, 127, 121, 123,
- 125, 125, 35, 36, 121, 126, 121, 121,
- 121, 121, 121, 121, 127, 121, 129, 121,
- 121, 121, 130, 131, 121, 36, 121, 126,
- 121, 121, 121, 121, 121, 129, 121, 122,
- 123, 124, 52, 35, 36, 121, 126, 121,
- 121, 37, 121, 121, 121, 127, 121, 129,
- 121, 121, 121, 132, 131, 121, 36, 121,
- 126, 121, 121, 121, 121, 121, 129, 121,
- 126, 121, 121, 133, 121, 126, 121, 126,
- 121, 126, 121, 121, 121, 121, 126, 121,
- 129, 121, 134, 121, 132, 132, 121, 36,
- 121, 126, 121, 121, 121, 121, 121, 129,
- 121, 129, 121, 121, 121, 132, 132, 121,
- 36, 121, 126, 121, 121, 121, 121, 121,
- 129, 121, 135, 40, 136, 137, 35, 36,
- 121, 126, 121, 40, 136, 137, 35, 36,
- 121, 126, 121, 136, 136, 35, 36, 121,
- 126, 121, 122, 123, 125, 125, 35, 36,
- 121, 126, 121, 121, 121, 121, 121, 121,
- 127, 121, 138, 139, 139, 35, 36, 121,
- 126, 121, 130, 140, 121, 36, 121, 126,
- 121, 132, 132, 121, 36, 121, 126, 121,
- 130, 121, 132, 132, 121, 36, 121, 126,
- 121, 132, 140, 121, 36, 121, 126, 121,
- 45, 46, 47, 48, 109, 105, 24, 25,
- 103, 51, 52, 52, 26, 103, 103, 45,
- 55, 103, 59, 141, 61, 62, 4, 1,
- 58, 63, 58, 58, 9, 58, 58, 58,
- 64, 58, 45, 46, 47, 48, 142, 143,
- 24, 144, 58, 145, 58, 52, 26, 58,
- 58, 45, 55, 58, 22, 146, 146, 24,
- 144, 58, 63, 58, 58, 26, 58, 145,
- 58, 58, 147, 58, 145, 58, 145, 58,
- 145, 58, 58, 58, 58, 145, 58, 45,
- 58, 71, 22, 146, 146, 24, 144, 58,
- 63, 58, 58, 58, 58, 58, 45, 58,
- 149, 148, 150, 150, 148, 43, 148, 151,
- 148, 150, 150, 148, 43, 148, 151, 148,
- 151, 148, 148, 152, 148, 151, 148, 151,
- 148, 151, 148, 148, 148, 148, 151, 148,
- 45, 120, 120, 120, 120, 120, 120, 120,
- 120, 120, 52, 120, 120, 120, 120, 45,
- 120, 0
-};
-
-static const unsigned char _indic_syllable_machine_trans_targs[] = {
- 39, 45, 50, 2, 51, 5, 6, 53,
- 57, 58, 39, 67, 11, 73, 68, 14,
- 15, 75, 80, 81, 84, 39, 89, 21,
- 95, 90, 98, 39, 24, 25, 97, 103,
- 39, 112, 30, 118, 113, 121, 33, 34,
- 120, 126, 39, 137, 39, 40, 60, 85,
- 87, 105, 106, 91, 107, 127, 128, 99,
- 135, 140, 39, 41, 43, 8, 59, 46,
- 54, 42, 1, 44, 48, 0, 47, 49,
- 52, 3, 4, 55, 7, 56, 39, 61,
- 63, 18, 83, 69, 76, 62, 9, 64,
- 78, 71, 65, 17, 82, 66, 10, 70,
- 72, 74, 12, 13, 77, 16, 79, 39,
- 86, 26, 88, 101, 93, 19, 104, 20,
- 92, 94, 96, 22, 23, 100, 27, 102,
- 39, 39, 108, 110, 28, 35, 114, 122,
- 109, 111, 124, 116, 29, 115, 117, 119,
- 31, 32, 123, 36, 125, 129, 130, 134,
- 131, 132, 37, 133, 39, 136, 38, 138,
- 139
-};
-
-static const char _indic_syllable_machine_trans_actions[] = {
- 1, 0, 2, 0, 2, 0, 0, 2,
- 2, 2, 3, 2, 0, 2, 0, 0,
- 0, 2, 2, 2, 2, 4, 2, 0,
- 5, 0, 5, 6, 0, 0, 5, 2,
- 7, 2, 0, 2, 0, 2, 0, 0,
- 2, 2, 8, 0, 11, 2, 2, 5,
- 0, 12, 12, 0, 2, 5, 2, 5,
- 2, 0, 13, 2, 0, 0, 2, 0,
- 2, 2, 0, 2, 2, 0, 0, 2,
- 2, 0, 0, 0, 0, 2, 14, 2,
- 0, 0, 2, 0, 2, 2, 0, 2,
- 2, 2, 2, 0, 2, 2, 0, 0,
- 2, 2, 0, 0, 0, 0, 2, 15,
- 5, 0, 5, 2, 2, 0, 5, 0,
- 0, 2, 5, 0, 0, 0, 0, 2,
- 16, 17, 2, 0, 0, 0, 0, 2,
- 2, 2, 2, 2, 0, 0, 2, 2,
- 0, 0, 0, 0, 2, 0, 18, 18,
- 0, 0, 0, 0, 19, 2, 0, 0,
- 0
-};
-
-static const char _indic_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, 9,
- 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, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0
-};
-
-static const char _indic_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, 10,
- 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, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0
-};
-
-static const short _indic_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 22, 22, 28, 22, 22,
- 22, 22, 22, 22, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 1, 43, 0,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 79, 79, 79, 79,
- 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 79, 79, 79, 104, 104, 104,
- 104, 104, 104, 104, 104, 104, 104, 104,
- 104, 104, 104, 104, 104, 104, 104, 104,
- 104, 121, 121, 122, 122, 122, 122, 122,
- 122, 122, 122, 122, 122, 122, 122, 122,
- 122, 122, 122, 122, 122, 122, 122, 104,
- 59, 59, 59, 59, 59, 59, 59, 149,
- 149, 149, 149, 149, 121
-};
-
-static const int indic_syllable_machine_start = 39;
-static const int indic_syllable_machine_first_final = 39;
-static const int indic_syllable_machine_error = -1;
-
-static const int indic_syllable_machine_en_main = 39;
-
-
-#line 46 "hb-ot-shape-complex-indic-machine.rl"
-
-
-
-#line 102 "hb-ot-shape-complex-indic-machine.rl"
-
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-static void
-find_syllables_indic (hb_buffer_t *buffer)
-{
- unsigned int p, pe, eof, ts, te, act;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 440 "hb-ot-shape-complex-indic-machine.hh"
- {
- cs = indic_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 122 "hb-ot-shape-complex-indic-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
-
-#line 456 "hb-ot-shape-complex-indic-machine.hh"
- {
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const unsigned char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _indic_syllable_machine_from_state_actions[cs] ) {
- case 10:
-#line 1 "NONE"
- {ts = p;}
- break;
-#line 470 "hb-ot-shape-complex-indic-machine.hh"
- }
-
- _keys = _indic_syllable_machine_trans_keys + (cs<<1);
- _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
-
- _slen = _indic_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
- ( info[p].indic_category()) <= _keys[1] ?
- ( info[p].indic_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _indic_syllable_machine_trans_targs[_trans];
-
- if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _indic_syllable_machine_trans_actions[_trans] ) {
- case 2:
-#line 1 "NONE"
- {te = p+1;}
- break;
- case 11:
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
- break;
- case 13:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
- break;
- case 14:
-#line 94 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
- break;
- case 17:
-#line 95 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
- break;
- case 19:
-#line 96 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
- break;
- case 15:
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_broken_cluster); }}
- break;
- case 16:
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
- break;
- case 1:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
- break;
- case 3:
-#line 94 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
- break;
- case 7:
-#line 95 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
- break;
- case 8:
-#line 96 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
- break;
- case 4:
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); }}
- break;
- case 6:
-#line 1 "NONE"
- { switch( act ) {
- case 1:
- {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
- break;
- case 5:
- {{p = ((te))-1;} found_syllable (indic_broken_cluster); }
- break;
- case 6:
- {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
- break;
- }
- }
- break;
- case 18:
-#line 1 "NONE"
- {te = p+1;}
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
- {act = 1;}
- break;
- case 5:
-#line 1 "NONE"
- {te = p+1;}
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
- {act = 5;}
- break;
- case 12:
-#line 1 "NONE"
- {te = p+1;}
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
- {act = 6;}
- break;
-#line 573 "hb-ot-shape-complex-indic-machine.hh"
- }
-
-_again:
- switch ( _indic_syllable_machine_to_state_actions[cs] ) {
- case 9:
-#line 1 "NONE"
- {ts = 0;}
- break;
-#line 582 "hb-ot-shape-complex-indic-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _indic_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 130 "hb-ot-shape-complex-indic-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
deleted file mode 100644
index 326aa9f96e..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+++ /dev/null
@@ -1,501 +0,0 @@
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
- *
- * on files with these headers:
- *
- * # IndicSyllabicCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # IndicPositionalCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
- */
-
-#include "hb.hh"
-
-#ifndef HB_NO_OT_SHAPE
-
-#include "hb-ot-shape-complex-indic.hh"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-
-#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 17 chars; Avagraha */
-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 91 chars; Bindu */
-#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
-#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 59 chars; Cantillation_Mark */
-#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2206 chars; Consonant */
-#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 14 chars; Consonant_Dead */
-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 70 chars; Consonant_Final */
-#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
-#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /* 1 chars; Consonant_Initial_Postfixed */
-#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 31 chars; Consonant_Medial */
-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 22 chars; Consonant_Placeholder */
-#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 3 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 10 chars; Consonant_Prefixed */
-#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 94 chars; Consonant_Subjoined */
-#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 1 chars; Consonant_Succeeding_Repha */
-#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 8 chars; Consonant_With_Stacker */
-#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 3 chars; Gemination_Mark */
-#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 12 chars; Invisible_Stacker */
-#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
-#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
-#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
-#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 32 chars; Nukta */
-#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 491 chars; Number */
-#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
-#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
-#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 25 chars; Pure_Killer */
-#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
-#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 25 chars; Syllable_Modifier */
-#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */
-#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 27 chars; Virama */
-#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 35 chars; Visarga */
-#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
-#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 686 chars; Vowel_Dependent */
-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 486 chars; Vowel_Independent */
-
-#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 352 chars; Bottom */
-#define IMC_BL INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT /* 1 chars; Bottom_And_Left */
-#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 4 chars; Bottom_And_Right */
-#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 64 chars; Left */
-#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 22 chars; Left_And_Right */
-#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
-#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */
-#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 290 chars; Right */
-#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 418 chars; Top */
-#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
-#define IMC_TBL INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT /* 2 chars; Top_And_Bottom_And_Left */
-#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
-#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */
-#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
-#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */
-
-#pragma GCC diagnostic pop
-
-#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
-
-
-static const uint16_t indic_table[] = {
-
-
-#define indic_offset_0x0028u 0
-
-
- /* Basic Latin */
-
- /* 0028 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x), _(x,x),
- /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x00b0u 24
-
-
- /* Latin-1 Supplement */
-
- /* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
-
-#define indic_offset_0x0900u 64
-
-
- /* Devanagari */
-
- /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L),
- /* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
- /* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
- /* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B),
- /* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0978 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
-
- /* Bengali */
-
- /* 0980 */ _(CP,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
- /* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
- /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
- /* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
- /* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
- /* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
- /* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
- /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(Bi,x), _(x,x), _(SM,T), _(x,x),
-
- /* Gurmukhi */
-
- /* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
- /* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
- /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L),
- /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
- /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
- /* 0A50 */ _(x,x), _(Ca,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
- /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x),
- /* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Gujarati */
-
- /* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
- /* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
- /* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
- /* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
- /* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AF8 */ _(x,x), _(C,x), _(Ca,T), _(Ca,T), _(Ca,T), _(N,T), _(N,T), _(N,T),
-
- /* Oriya */
-
- /* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
- /* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
- /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
- /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
- /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,T), _(M,TR),
- /* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
- /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Tamil */
-
- /* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
- /* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
- /* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
- /* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
- /* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
- /* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
- /* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
- /* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
- /* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
- /* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Telugu */
-
- /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(Bi,T), _(VI,x), _(VI,x), _(VI,x),
- /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
- /* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,T), _(M,T),
- /* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
- /* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
- /* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
- /* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(CD,x), _(x,x), _(x,x),
- /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Kannada */
-
- /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
- /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
- /* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
- /* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
- /* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
- /* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(C,x), _(x,x),
- /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Malayalam */
-
- /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(Bi,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
- /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0D38 */ _(C,x), _(C,x), _(C,x), _(PK,T), _(PK,T), _(A,x), _(M,R), _(M,R),
- /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
- /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,T), _(x,x),
- /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(M,R),
- /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
- /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
-
- /* Sinhala */
-
- /* 0D80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
- /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x),
- /* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
- /* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
- /* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x),
- /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR),_(M,TLR), _(M,LR), _(M,R),
- /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x1000u 1336
-
-
- /* Myanmar */
-
- /* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
- /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B),
- /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R),_(CM,TBL), _(CM,B), _(CM,B), _(C,x),
- /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(CP,x), _(x,x), _(x,x), _(CP,x), _(x,x),
- /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
- /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,B), _(CM,B),
- /* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R),
- /* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x),
- /* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
- /* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R),
- /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R),
- /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x),
-
-#define indic_offset_0x1780u 1496
-
-
- /* Khmer */
-
- /* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
- /* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
- /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
- /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
- /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(SM,T), _(x,x), _(x,x),
- /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x1cd0u 1608
-
-
- /* Vedic Extensions */
-
- /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
- /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
- /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O),
- /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x),
- /* 1CF0 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
- /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x2008u 1656
-
-
- /* General Punctuation */
-
- /* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
- /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x2070u 1672
-
-
- /* Superscripts and Subscripts */
-
- /* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x),
- /* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0xa8e0u 1696
-
-
- /* Devanagari Extended */
-
- /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
- /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
- /* A8F0 */ _(Ca,T), _(Ca,T), _(Bi,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(M,T),
-
-#define indic_offset_0xa9e0u 1728
-
-
- /* Myanmar Extended-B */
-
- /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x),
- /* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
-
-#define indic_offset_0xaa60u 1760
-
-
- /* Myanmar Extended-A */
-
- /* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(CP,x), _(CP,x), _(CP,x), _(x,x),
- /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
-
-}; /* Table items: 1792; occupancy: 71% */
-
-uint16_t
-hb_indic_get_categories (hb_codepoint_t u)
-{
- switch (u >> 12)
- {
- case 0x0u:
- if (unlikely (u == 0x00A0u)) return _(CP,x);
- if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
- if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
- break;
-
- case 0x1u:
- if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
- break;
-
- case 0x2u:
- if (unlikely (u == 0x25CCu)) return _(CP,x);
- if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
- if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
- break;
-
- case 0xAu:
- if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
- if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
- if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
- break;
-
- default:
- break;
- }
- return _(x,x);
-}
-
-#undef _
-
-#undef ISC_A
-#undef ISC_Bi
-#undef ISC_BJN
-#undef ISC_Ca
-#undef ISC_C
-#undef ISC_CD
-#undef ISC_CF
-#undef ISC_CHL
-#undef ISC_CIP
-#undef ISC_CK
-#undef ISC_CM
-#undef ISC_CP
-#undef ISC_CPR
-#undef ISC_CPrf
-#undef ISC_CS
-#undef ISC_CSR
-#undef ISC_CWS
-#undef ISC_GM
-#undef ISC_IS
-#undef ISC_ZWJ
-#undef ISC_ML
-#undef ISC_ZWNJ
-#undef ISC_N
-#undef ISC_Nd
-#undef ISC_NJ
-#undef ISC_x
-#undef ISC_PK
-#undef ISC_RS
-#undef ISC_SM
-#undef ISC_TL
-#undef ISC_TM
-#undef ISC_V
-#undef ISC_Vs
-#undef ISC_Vo
-#undef ISC_M
-#undef ISC_VI
-
-#undef IMC_B
-#undef IMC_BL
-#undef IMC_BR
-#undef IMC_L
-#undef IMC_LR
-#undef IMC_x
-#undef IMC_O
-#undef IMC_R
-#undef IMC_T
-#undef IMC_TB
-#undef IMC_TBL
-#undef IMC_TBR
-#undef IMC_TL
-#undef IMC_TLR
-#undef IMC_TR
-#undef IMC_VOL
-
-#endif
-
-/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
deleted file mode 100644
index da77a2887c..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright © 2012 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-syllabic.hh"
-
-
-/* buffer var allocations */
-#define indic_category() complex_var_u8_category() /* indic_category_t */
-#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */
-
-
-/* Cateories used in the OpenType spec:
- * https://docs.microsoft.com/en-us/typography/script-development/devanagari
- */
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum indic_category_t {
- OT_X = 0,
- OT_C = 1,
- OT_V = 2,
- OT_N = 3,
- OT_H = 4,
- OT_ZWNJ = 5,
- OT_ZWJ = 6,
- OT_M = 7,
- OT_SM = 8,
- /* OT_VD = 9, UNUSED; we use OT_A instead. */
- OT_A = 10,
- OT_PLACEHOLDER = 11,
- OT_DOTTEDCIRCLE = 12,
- OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
- OT_Coeng = 14, /* Khmer-style Virama. */
- OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
- OT_Ra = 16,
- OT_CM = 17, /* Consonant-Medial. */
- OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
- OT_CS = 19,
-
- /* The following are used by Khmer & Myanmar shapers. Defined
- * here for them to share. */
- OT_VAbv = 26,
- OT_VBlw = 27,
- OT_VPre = 28,
- OT_VPst = 29,
-};
-
-#define MEDIAL_FLAGS (FLAG (OT_CM))
-
-/* Note:
- *
- * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
- * cannot happen in a consonant syllable. The plus side however is, we can call the
- * consonant syllable logic from the vowel syllable function and get it all right! */
-#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
-#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
-
-
-/* Visual positions in a syllable from left to right. */
-enum indic_position_t {
- POS_START = 0,
-
- POS_RA_TO_BECOME_REPH = 1,
- POS_PRE_M = 2,
- POS_PRE_C = 3,
-
- POS_BASE_C = 4,
- POS_AFTER_MAIN = 5,
-
- POS_ABOVE_C = 6,
-
- POS_BEFORE_SUB = 7,
- POS_BELOW_C = 8,
- POS_AFTER_SUB = 9,
-
- POS_BEFORE_POST = 10,
- POS_POST_C = 11,
- POS_AFTER_POST = 12,
-
- POS_FINAL_C = 13,
- POS_SMVD = 14,
-
- POS_END = 15
-};
-
-/* Categories used in IndicSyllabicCategory.txt from UCD. */
-enum indic_syllabic_category_t {
- INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
-
- INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
- INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
- INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */
- INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
- INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */
- INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
- INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_CM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_CS,
- INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */
- INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
- INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
- INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
- INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
- INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
- INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
- INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
- INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
- INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
- INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_SM,
- INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
- INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
- INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
- INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
- INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
- INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
- INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
-};
-
-/* Categories used in IndicSMatraCategory.txt from UCD */
-enum indic_matra_category_t {
- INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END,
-
- INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C,
- INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C,
- INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C,
- INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C,
-
- /* These should resolve to the position of the last part of the split sequence. */
- INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
- INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
- INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM,
- INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT = INDIC_MATRA_CATEGORY_BOTTOM,
- INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
- INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP,
- INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
- INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
-
- INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
- INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
-};
-
-#define INDIC_COMBINE_CATEGORIES(S,M) \
- ( \
- static_assert_expr (S < 255 && M < 255) + \
- ( S | \
- ( \
- ( \
- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
- S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
- S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
- S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
- S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
- false \
- ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
- ) << 8 \
- ) \
- ) \
- )
-
-HB_INTERNAL uint16_t
-hb_indic_get_categories (hb_codepoint_t u);
-
-
-static inline bool
-is_one_of (const hb_glyph_info_t &info, unsigned int flags)
-{
- /* If it ligated, all bets are off. */
- if (_hb_glyph_info_ligated (&info)) return false;
- return !!(FLAG_UNSAFE (info.indic_category()) & flags);
-}
-
-static inline bool
-is_joiner (const hb_glyph_info_t &info)
-{
- return is_one_of (info, JOINER_FLAGS);
-}
-
-static inline bool
-is_consonant (const hb_glyph_info_t &info)
-{
- return is_one_of (info, CONSONANT_FLAGS);
-}
-
-static inline bool
-is_halant (const hb_glyph_info_t &info)
-{
- return is_one_of (info, FLAG (OT_H));
-}
-
-#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
-
-#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
-#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
-#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
-#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
-#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
-#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
-#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
-#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
-#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
-#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
-
-
-#define MATRA_POS_LEFT(u) POS_PRE_M
-#define MATRA_POS_RIGHT(u) ( \
- IS_DEVA(u) ? POS_AFTER_SUB : \
- IS_BENG(u) ? POS_AFTER_POST : \
- IS_GURU(u) ? POS_AFTER_POST : \
- IS_GUJR(u) ? POS_AFTER_POST : \
- IS_ORYA(u) ? POS_AFTER_POST : \
- IS_TAML(u) ? POS_AFTER_POST : \
- IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
- IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
- IS_MLYM(u) ? POS_AFTER_POST : \
- IS_SINH(u) ? POS_AFTER_SUB : \
- /*default*/ POS_AFTER_SUB \
- )
-#define MATRA_POS_TOP(u) ( /* BENG and MLYM don't have top matras. */ \
- IS_DEVA(u) ? POS_AFTER_SUB : \
- IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
- IS_GUJR(u) ? POS_AFTER_SUB : \
- IS_ORYA(u) ? POS_AFTER_MAIN : \
- IS_TAML(u) ? POS_AFTER_SUB : \
- IS_TELU(u) ? POS_BEFORE_SUB : \
- IS_KNDA(u) ? POS_BEFORE_SUB : \
- IS_SINH(u) ? POS_AFTER_SUB : \
- /*default*/ POS_AFTER_SUB \
- )
-#define MATRA_POS_BOTTOM(u) ( \
- IS_DEVA(u) ? POS_AFTER_SUB : \
- IS_BENG(u) ? POS_AFTER_SUB : \
- IS_GURU(u) ? POS_AFTER_POST : \
- IS_GUJR(u) ? POS_AFTER_POST : \
- IS_ORYA(u) ? POS_AFTER_SUB : \
- IS_TAML(u) ? POS_AFTER_POST : \
- IS_TELU(u) ? POS_BEFORE_SUB : \
- IS_KNDA(u) ? POS_BEFORE_SUB : \
- IS_MLYM(u) ? POS_AFTER_POST : \
- IS_SINH(u) ? POS_AFTER_SUB : \
- /*default*/ POS_AFTER_SUB \
- )
-
-static inline indic_position_t
-matra_position_indic (hb_codepoint_t u, indic_position_t side)
-{
- switch ((int) side)
- {
- case POS_PRE_C: return MATRA_POS_LEFT (u);
- case POS_POST_C: return MATRA_POS_RIGHT (u);
- case POS_ABOVE_C: return MATRA_POS_TOP (u);
- case POS_BELOW_C: return MATRA_POS_BOTTOM (u);
- }
- return side;
-}
-
-/* XXX
- * This is a hack for now. We should move this data into the main Indic table.
- * Or completely remove it and just check in the tables.
- */
-static const hb_codepoint_t ra_chars[] = {
- 0x0930u, /* Devanagari */
- 0x09B0u, /* Bengali */
- 0x09F0u, /* Bengali */
- 0x0A30u, /* Gurmukhi */ /* No Reph */
- 0x0AB0u, /* Gujarati */
- 0x0B30u, /* Oriya */
- 0x0BB0u, /* Tamil */ /* No Reph */
- 0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */
- 0x0CB0u, /* Kannada */
- 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
-
- 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
-};
-
-static inline bool
-is_ra (hb_codepoint_t u)
-{
- return hb_array (ra_chars).lfind (u);
-}
-
-static inline void
-set_indic_properties (hb_glyph_info_t &info)
-{
- hb_codepoint_t u = info.codepoint;
- unsigned int type = hb_indic_get_categories (u);
- indic_category_t cat = (indic_category_t) (type & 0xFFu);
- indic_position_t pos = (indic_position_t) (type >> 8);
-
-
- /*
- * Re-assign category
- */
-
- /* The following act more like the Bindus. */
- if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953u, 0x0954u)))
- cat = OT_SM;
- /* The following act like consonants. */
- else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72u, 0x0A73u,
- 0x1CF5u, 0x1CF6u)))
- cat = OT_C;
- /* TODO: The following should only be allowed after a Visarga.
- * For now, just treat them like regular tone marks. */
- else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2u, 0x1CE8u)))
- cat = OT_A;
- /* TODO: The following should only be allowed after some of
- * the nasalization marks, maybe only for U+1CE9..U+1CF1.
- * For now, just treat them like tone marks. */
- else if (unlikely (u == 0x1CEDu))
- cat = OT_A;
- /* The following take marks in standalone clusters, similar to Avagraha. */
- else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2u, 0xA8F7u,
- 0x1CE9u, 0x1CECu,
- 0x1CEEu, 0x1CF1u)))
- {
- cat = OT_Symbol;
- static_assert (((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol), "");
- }
- else if (unlikely (u == 0x0A51u))
- {
- /* https://github.com/harfbuzz/harfbuzz/issues/524 */
- cat = OT_M;
- pos = POS_BELOW_C;
- }
-
- /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
- * so the Indic shaper needs to know their categories. */
- else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM;
- else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
-
- else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
- else if (unlikely (u == 0x0B55u)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/2849 */
-
- 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;
-
-
- /*
- * Re-assign position.
- */
-
- if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS))
- {
- pos = POS_BASE_C;
- if (is_ra (u))
- cat = OT_Ra;
- }
- else if (cat == OT_M)
- {
- pos = matra_position_indic (u, pos);
- }
- else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) /* | FLAG (OT_VD) */ | FLAG (OT_A) | FLAG (OT_Symbol))))
- {
- pos = POS_SMVD;
- }
-
- if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
-
-
-
- info.indic_category() = cat;
- info.indic_position() = pos;
-}
-
-struct hb_indic_would_substitute_feature_t
-{
- void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
- {
- zero_context = zero_context_;
- map->get_stage_lookups (0/*GSUB*/,
- map->get_feature_stage (0/*GSUB*/, feature_tag),
- &lookups, &count);
- }
-
- bool would_substitute (const hb_codepoint_t *glyphs,
- unsigned int glyphs_count,
- hb_face_t *face) const
- {
- for (unsigned int i = 0; i < count; i++)
- if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context))
- return true;
- return false;
- }
-
- private:
- const hb_ot_map_t::lookup_map_t *lookups;
- unsigned int count;
- bool zero_context;
-};
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
deleted file mode 100644
index c52f72f394..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
+++ /dev/null
@@ -1,396 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-khmer-machine.rl"
-/*
- * Copyright © 2011,2012 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-
-#include "hb.hh"
-
-enum khmer_syllable_type_t {
- khmer_consonant_syllable,
- khmer_broken_cluster,
- khmer_non_khmer_cluster,
-};
-
-
-#line 42 "hb-ot-shape-complex-khmer-machine.hh"
-#define khmer_syllable_machine_ex_C 1u
-#define khmer_syllable_machine_ex_Coeng 14u
-#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
-#define khmer_syllable_machine_ex_PLACEHOLDER 11u
-#define khmer_syllable_machine_ex_Ra 16u
-#define khmer_syllable_machine_ex_Robatic 20u
-#define khmer_syllable_machine_ex_V 2u
-#define khmer_syllable_machine_ex_VAbv 26u
-#define khmer_syllable_machine_ex_VBlw 27u
-#define khmer_syllable_machine_ex_VPre 28u
-#define khmer_syllable_machine_ex_VPst 29u
-#define khmer_syllable_machine_ex_Xgroup 21u
-#define khmer_syllable_machine_ex_Ygroup 22u
-#define khmer_syllable_machine_ex_ZWJ 6u
-#define khmer_syllable_machine_ex_ZWNJ 5u
-
-
-#line 60 "hb-ot-shape-complex-khmer-machine.hh"
-static const unsigned char _khmer_syllable_machine_trans_keys[] = {
- 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
- 5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u,
- 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u,
- 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u,
- 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u,
- 0
-};
-
-static const char _khmer_syllable_machine_key_spans[] = {
- 22, 17, 22, 17, 16, 17, 22, 17,
- 22, 17, 17, 22, 17, 16, 17, 22,
- 17, 22, 17, 22, 29, 25, 25, 25,
- 1, 18, 25, 25, 25, 16, 22, 25,
- 25, 1, 18, 25, 25, 16, 25, 25
-};
-
-static const short _khmer_syllable_machine_index_offsets[] = {
- 0, 23, 41, 64, 82, 99, 117, 140,
- 158, 181, 199, 217, 240, 258, 275, 293,
- 316, 334, 357, 375, 398, 428, 454, 480,
- 506, 508, 527, 553, 579, 605, 622, 645,
- 671, 697, 699, 718, 744, 770, 787, 813
-};
-
-static const char _khmer_syllable_machine_indicies[] = {
- 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 2,
- 3, 0, 0, 0, 0, 4, 0, 1,
- 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 3,
- 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 3, 0, 0, 0, 0, 4, 0,
- 5, 5, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 0, 6, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 6, 0, 7, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 0, 9, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 10, 0, 0,
- 0, 0, 4, 0, 9, 9, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 10, 0, 11, 11,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 12, 0,
- 0, 0, 0, 4, 0, 11, 11, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 0, 14,
- 14, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 15,
- 13, 14, 14, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 15, 16, 16, 16, 16, 17, 16,
- 18, 18, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 17, 16, 19, 19, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 19, 16, 20, 20, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 21, 16, 22, 22, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 23, 16, 16,
- 16, 16, 17, 16, 22, 22, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 23, 16, 24, 24,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 25, 16,
- 16, 16, 16, 17, 16, 24, 24, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 25, 16, 14,
- 14, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 26, 15,
- 16, 16, 16, 16, 17, 16, 28, 28,
- 27, 27, 29, 29, 27, 27, 27, 27,
- 2, 2, 27, 30, 27, 28, 27, 27,
- 27, 27, 15, 19, 27, 27, 27, 17,
- 23, 25, 21, 27, 32, 32, 31, 31,
- 31, 31, 31, 31, 31, 33, 31, 31,
- 31, 31, 31, 2, 3, 6, 31, 31,
- 31, 4, 10, 12, 8, 31, 34, 34,
- 31, 31, 31, 31, 31, 31, 31, 35,
- 31, 31, 31, 31, 31, 31, 3, 6,
- 31, 31, 31, 4, 10, 12, 8, 31,
- 5, 5, 31, 31, 31, 31, 31, 31,
- 31, 35, 31, 31, 31, 31, 31, 31,
- 4, 6, 31, 31, 31, 31, 31, 31,
- 8, 31, 6, 31, 7, 7, 31, 31,
- 31, 31, 31, 31, 31, 35, 31, 31,
- 31, 31, 31, 31, 8, 6, 31, 36,
- 36, 31, 31, 31, 31, 31, 31, 31,
- 35, 31, 31, 31, 31, 31, 31, 10,
- 6, 31, 31, 31, 4, 31, 31, 8,
- 31, 37, 37, 31, 31, 31, 31, 31,
- 31, 31, 35, 31, 31, 31, 31, 31,
- 31, 12, 6, 31, 31, 31, 4, 10,
- 31, 8, 31, 34, 34, 31, 31, 31,
- 31, 31, 31, 31, 33, 31, 31, 31,
- 31, 31, 31, 3, 6, 31, 31, 31,
- 4, 10, 12, 8, 31, 28, 28, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 28, 31, 14, 14,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 15, 38,
- 38, 38, 38, 17, 38, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 41, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 18,
- 18, 39, 39, 39, 39, 39, 39, 39,
- 41, 39, 39, 39, 39, 39, 39, 17,
- 19, 39, 39, 39, 39, 39, 39, 21,
- 39, 19, 39, 20, 20, 39, 39, 39,
- 39, 39, 39, 39, 41, 39, 39, 39,
- 39, 39, 39, 21, 19, 39, 42, 42,
- 39, 39, 39, 39, 39, 39, 39, 41,
- 39, 39, 39, 39, 39, 39, 23, 19,
- 39, 39, 39, 17, 39, 39, 21, 39,
- 43, 43, 39, 39, 39, 39, 39, 39,
- 39, 41, 39, 39, 39, 39, 39, 39,
- 25, 19, 39, 39, 39, 17, 23, 39,
- 21, 39, 44, 44, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 44, 39, 45, 45, 39, 39, 39,
- 39, 39, 39, 39, 30, 39, 39, 39,
- 39, 39, 26, 15, 19, 39, 39, 39,
- 17, 23, 25, 21, 39, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 30, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 0
-};
-
-static const char _khmer_syllable_machine_trans_targs[] = {
- 20, 1, 28, 22, 23, 3, 24, 5,
- 25, 7, 26, 9, 27, 20, 10, 31,
- 20, 32, 12, 33, 14, 34, 16, 35,
- 18, 36, 39, 20, 21, 30, 37, 20,
- 0, 29, 2, 4, 6, 8, 20, 20,
- 11, 13, 15, 17, 38, 19
-};
-
-static const char _khmer_syllable_machine_trans_actions[] = {
- 1, 0, 2, 2, 2, 0, 0, 0,
- 2, 0, 2, 0, 2, 3, 0, 4,
- 5, 2, 0, 0, 0, 2, 0, 2,
- 0, 2, 4, 8, 2, 9, 0, 10,
- 0, 0, 0, 0, 0, 0, 11, 12,
- 0, 0, 0, 0, 4, 0
-};
-
-static const char _khmer_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, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const char _khmer_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, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const unsigned char _khmer_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 14, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 0, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 39, 40,
- 40, 40, 40, 40, 40, 40, 40, 40
-};
-
-static const int khmer_syllable_machine_start = 20;
-static const int khmer_syllable_machine_first_final = 20;
-static const int khmer_syllable_machine_error = -1;
-
-static const int khmer_syllable_machine_en_main = 20;
-
-
-#line 43 "hb-ot-shape-complex-khmer-machine.rl"
-
-
-
-#line 86 "hb-ot-shape-complex-khmer-machine.rl"
-
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-static void
-find_syllables_khmer (hb_buffer_t *buffer)
-{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 266 "hb-ot-shape-complex-khmer-machine.hh"
- {
- cs = khmer_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 106 "hb-ot-shape-complex-khmer-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
-
-#line 282 "hb-ot-shape-complex-khmer-machine.hh"
- {
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
- case 7:
-#line 1 "NONE"
- {ts = p;}
- break;
-#line 296 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
- _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
-
- _slen = _khmer_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
- ( info[p].khmer_category()) <= _keys[1] ?
- ( info[p].khmer_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _khmer_syllable_machine_trans_targs[_trans];
-
- if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
- case 2:
-#line 1 "NONE"
- {te = p+1;}
- break;
- case 8:
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
- break;
- case 10:
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
- break;
- case 12:
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (khmer_broken_cluster); }}
- break;
- case 11:
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
- break;
- case 1:
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
- break;
- case 5:
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); }}
- break;
- case 3:
-#line 1 "NONE"
- { switch( act ) {
- case 2:
- {{p = ((te))-1;} found_syllable (khmer_broken_cluster); }
- break;
- case 3:
- {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
- break;
- }
- }
- break;
- case 4:
-#line 1 "NONE"
- {te = p+1;}
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 2;}
- break;
- case 9:
-#line 1 "NONE"
- {te = p+1;}
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 3;}
- break;
-#line 366 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
-_again:
- switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
- case 6:
-#line 1 "NONE"
- {ts = 0;}
- break;
-#line 375 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 114 "hb-ot-shape-complex-khmer-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
deleted file mode 100644
index 35bfbb64d5..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright © 2018 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-indic.hh"
-
-
-/* buffer var allocations */
-#define khmer_category() indic_category() /* khmer_category_t */
-
-
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum khmer_category_t
-{
- OT_Robatic = 20,
- OT_Xgroup = 21,
- OT_Ygroup = 22,
- //OT_VAbv = 26,
- //OT_VBlw = 27,
- //OT_VPre = 28,
- //OT_VPst = 29,
-};
-
-using khmer_position_t = indic_position_t;
-
-static inline void
-set_khmer_properties (hb_glyph_info_t &info)
-{
- hb_codepoint_t u = info.codepoint;
- unsigned int type = hb_indic_get_categories (u);
- khmer_category_t cat = (khmer_category_t) (type & 0xFFu);
- khmer_position_t pos = (khmer_position_t) (type >> 8);
-
-
- /*
- * Re-assign category
- *
- * These categories are experimentally extracted from what Uniscribe allows.
- */
- switch (u)
- {
- case 0x179Au:
- cat = (khmer_category_t) OT_Ra;
- break;
-
- case 0x17CCu:
- case 0x17C9u:
- case 0x17CAu:
- cat = OT_Robatic;
- break;
-
- case 0x17C6u:
- case 0x17CBu:
- case 0x17CDu:
- case 0x17CEu:
- case 0x17CFu:
- case 0x17D0u:
- case 0x17D1u:
- cat = OT_Xgroup;
- break;
-
- case 0x17C7u:
- case 0x17C8u:
- case 0x17DDu:
- case 0x17D3u: /* Just guessing. Uniscribe doesn't categorize it. */
- cat = OT_Ygroup;
- break;
- }
-
- /*
- * Re-assign position.
- */
- if (cat == (khmer_category_t) OT_M)
- switch ((int) pos)
- {
- case POS_PRE_C: cat = (khmer_category_t) OT_VPre; break;
- case POS_BELOW_C: cat = (khmer_category_t) OT_VBlw; break;
- case POS_ABOVE_C: cat = (khmer_category_t) OT_VAbv; break;
- case POS_POST_C: cat = (khmer_category_t) OT_VPst; break;
- default: assert (0);
- }
-
- info.khmer_category() = cat;
-}
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
deleted file mode 100644
index f4ef33004d..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
+++ /dev/null
@@ -1,492 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
-/*
- * Copyright © 2011,2012 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-
-#include "hb.hh"
-
-enum myanmar_syllable_type_t {
- myanmar_consonant_syllable,
- myanmar_punctuation_cluster,
- myanmar_broken_cluster,
- myanmar_non_myanmar_cluster,
-};
-
-
-#line 43 "hb-ot-shape-complex-myanmar-machine.hh"
-#define myanmar_syllable_machine_ex_A 10u
-#define myanmar_syllable_machine_ex_As 18u
-#define myanmar_syllable_machine_ex_C 1u
-#define myanmar_syllable_machine_ex_CS 19u
-#define myanmar_syllable_machine_ex_D 32u
-#define myanmar_syllable_machine_ex_D0 20u
-#define myanmar_syllable_machine_ex_DB 3u
-#define myanmar_syllable_machine_ex_GB 11u
-#define myanmar_syllable_machine_ex_H 4u
-#define myanmar_syllable_machine_ex_IV 2u
-#define myanmar_syllable_machine_ex_MH 21u
-#define myanmar_syllable_machine_ex_ML 33u
-#define myanmar_syllable_machine_ex_MR 22u
-#define myanmar_syllable_machine_ex_MW 23u
-#define myanmar_syllable_machine_ex_MY 24u
-#define myanmar_syllable_machine_ex_P 31u
-#define myanmar_syllable_machine_ex_PT 25u
-#define myanmar_syllable_machine_ex_Ra 16u
-#define myanmar_syllable_machine_ex_V 8u
-#define myanmar_syllable_machine_ex_VAbv 26u
-#define myanmar_syllable_machine_ex_VBlw 27u
-#define myanmar_syllable_machine_ex_VPre 28u
-#define myanmar_syllable_machine_ex_VPst 29u
-#define myanmar_syllable_machine_ex_VS 30u
-#define myanmar_syllable_machine_ex_ZWJ 6u
-#define myanmar_syllable_machine_ex_ZWNJ 5u
-
-
-#line 72 "hb-ot-shape-complex-myanmar-machine.hh"
-static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
- 1u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
- 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u,
- 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u, 3u, 33u,
- 3u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
- 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u,
- 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u,
- 3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 1u, 33u, 1u, 32u, 8u, 8u,
- 0
-};
-
-static const char _myanmar_syllable_machine_key_spans[] = {
- 33, 31, 25, 4, 25, 23, 21, 21,
- 31, 27, 27, 27, 31, 16, 31, 31,
- 27, 27, 27, 28, 27, 31, 31, 31,
- 31, 31, 25, 4, 25, 23, 21, 21,
- 31, 27, 27, 27, 31, 16, 31, 31,
- 31, 27, 27, 27, 28, 27, 31, 31,
- 31, 31, 31, 31, 31, 33, 32, 1
-};
-
-static const short _myanmar_syllable_machine_index_offsets[] = {
- 0, 34, 66, 92, 97, 123, 147, 169,
- 191, 223, 251, 279, 307, 339, 356, 388,
- 420, 448, 476, 504, 533, 561, 593, 625,
- 657, 689, 721, 747, 752, 778, 802, 824,
- 846, 878, 906, 934, 962, 994, 1011, 1043,
- 1075, 1107, 1135, 1163, 1191, 1220, 1248, 1280,
- 1312, 1344, 1376, 1408, 1440, 1472, 1506, 1539
-};
-
-static const char _myanmar_syllable_machine_indicies[] = {
- 1, 1, 2, 3, 4, 4, 0, 5,
- 0, 6, 1, 0, 0, 0, 0, 7,
- 0, 8, 9, 0, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 20, 1,
- 21, 0, 23, 24, 25, 25, 22, 26,
- 22, 27, 22, 22, 22, 22, 22, 22,
- 22, 28, 22, 22, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 22, 22,
- 39, 22, 25, 25, 22, 26, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 40,
- 22, 22, 22, 22, 22, 22, 33, 22,
- 22, 22, 37, 22, 25, 25, 22, 26,
- 22, 25, 25, 22, 26, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 33, 22, 22,
- 22, 37, 22, 41, 22, 25, 25, 22,
- 26, 22, 33, 22, 22, 22, 22, 22,
- 22, 22, 42, 22, 22, 22, 22, 22,
- 22, 33, 22, 25, 25, 22, 26, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 42, 22, 22, 22, 22, 22, 22, 33,
- 22, 25, 25, 22, 26, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 33, 22, 23,
- 22, 25, 25, 22, 26, 22, 27, 22,
- 22, 22, 22, 22, 22, 22, 43, 22,
- 22, 44, 22, 22, 22, 33, 45, 22,
- 22, 37, 22, 22, 22, 43, 22, 23,
- 22, 25, 25, 22, 26, 22, 27, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 33, 22, 22,
- 22, 37, 22, 23, 22, 25, 25, 22,
- 26, 22, 27, 22, 22, 22, 22, 22,
- 22, 22, 43, 22, 22, 22, 22, 22,
- 22, 33, 45, 22, 22, 37, 22, 23,
- 22, 25, 25, 22, 26, 22, 27, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 33, 45, 22,
- 22, 37, 22, 23, 22, 25, 25, 22,
- 26, 22, 27, 22, 22, 22, 22, 22,
- 22, 22, 43, 22, 22, 22, 22, 22,
- 22, 33, 45, 22, 22, 37, 22, 22,
- 22, 43, 22, 1, 1, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 1, 22, 23, 22, 25, 25,
- 22, 26, 22, 27, 22, 22, 22, 22,
- 22, 22, 22, 28, 22, 22, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 22,
- 22, 22, 39, 22, 23, 22, 25, 25,
- 22, 26, 22, 27, 22, 22, 22, 22,
- 22, 22, 22, 46, 22, 22, 22, 22,
- 22, 22, 33, 34, 35, 36, 37, 22,
- 22, 22, 39, 22, 23, 22, 25, 25,
- 22, 26, 22, 27, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 33, 34, 35, 36, 37, 22,
- 23, 22, 25, 25, 22, 26, 22, 27,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 33, 34,
- 35, 22, 37, 22, 23, 22, 25, 25,
- 22, 26, 22, 27, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 33, 22, 35, 22, 37, 22,
- 23, 22, 25, 25, 22, 26, 22, 27,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 33, 34,
- 35, 36, 37, 46, 22, 23, 22, 25,
- 25, 22, 26, 22, 27, 22, 22, 22,
- 22, 22, 22, 22, 46, 22, 22, 22,
- 22, 22, 22, 33, 34, 35, 36, 37,
- 22, 23, 22, 25, 25, 22, 26, 22,
- 27, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 29, 22, 31, 22, 33,
- 34, 35, 36, 37, 22, 22, 22, 39,
- 22, 23, 22, 25, 25, 22, 26, 22,
- 27, 22, 22, 22, 22, 22, 22, 22,
- 46, 22, 22, 29, 22, 22, 22, 33,
- 34, 35, 36, 37, 22, 22, 22, 39,
- 22, 23, 22, 25, 25, 22, 26, 22,
- 27, 22, 22, 22, 22, 22, 22, 22,
- 47, 22, 22, 29, 30, 31, 22, 33,
- 34, 35, 36, 37, 22, 22, 22, 39,
- 22, 23, 22, 25, 25, 22, 26, 22,
- 27, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 29, 30, 31, 22, 33,
- 34, 35, 36, 37, 22, 22, 22, 39,
- 22, 23, 24, 25, 25, 22, 26, 22,
- 27, 22, 22, 22, 22, 22, 22, 22,
- 28, 22, 22, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 22, 22, 22, 39,
- 22, 49, 49, 48, 5, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 50, 48,
- 48, 48, 48, 48, 48, 14, 48, 48,
- 48, 18, 48, 49, 49, 48, 5, 48,
- 49, 49, 48, 5, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 14, 48, 48, 48,
- 18, 48, 51, 48, 49, 49, 48, 5,
- 48, 14, 48, 48, 48, 48, 48, 48,
- 48, 52, 48, 48, 48, 48, 48, 48,
- 14, 48, 49, 49, 48, 5, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 52,
- 48, 48, 48, 48, 48, 48, 14, 48,
- 49, 49, 48, 5, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 14, 48, 2, 48,
- 49, 49, 48, 5, 48, 6, 48, 48,
- 48, 48, 48, 48, 48, 53, 48, 48,
- 54, 48, 48, 48, 14, 55, 48, 48,
- 18, 48, 48, 48, 53, 48, 2, 48,
- 49, 49, 48, 5, 48, 6, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 14, 48, 48, 48,
- 18, 48, 2, 48, 49, 49, 48, 5,
- 48, 6, 48, 48, 48, 48, 48, 48,
- 48, 53, 48, 48, 48, 48, 48, 48,
- 14, 55, 48, 48, 18, 48, 2, 48,
- 49, 49, 48, 5, 48, 6, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 14, 55, 48, 48,
- 18, 48, 2, 48, 49, 49, 48, 5,
- 48, 6, 48, 48, 48, 48, 48, 48,
- 48, 53, 48, 48, 48, 48, 48, 48,
- 14, 55, 48, 48, 18, 48, 48, 48,
- 53, 48, 56, 56, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 56, 48, 2, 3, 49, 49, 48,
- 5, 48, 6, 48, 48, 48, 48, 48,
- 48, 48, 8, 48, 48, 10, 11, 12,
- 13, 14, 15, 16, 17, 18, 19, 48,
- 48, 21, 48, 2, 48, 49, 49, 48,
- 5, 48, 6, 48, 48, 48, 48, 48,
- 48, 48, 8, 48, 48, 10, 11, 12,
- 13, 14, 15, 16, 17, 18, 48, 48,
- 48, 21, 48, 2, 48, 49, 49, 48,
- 5, 48, 6, 48, 48, 48, 48, 48,
- 48, 48, 57, 48, 48, 48, 48, 48,
- 48, 14, 15, 16, 17, 18, 48, 48,
- 48, 21, 48, 2, 48, 49, 49, 48,
- 5, 48, 6, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 14, 15, 16, 17, 18, 48, 2,
- 48, 49, 49, 48, 5, 48, 6, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 14, 15, 16,
- 48, 18, 48, 2, 48, 49, 49, 48,
- 5, 48, 6, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 14, 48, 16, 48, 18, 48, 2,
- 48, 49, 49, 48, 5, 48, 6, 48,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 14, 15, 16,
- 17, 18, 57, 48, 2, 48, 49, 49,
- 48, 5, 48, 6, 48, 48, 48, 48,
- 48, 48, 48, 57, 48, 48, 48, 48,
- 48, 48, 14, 15, 16, 17, 18, 48,
- 2, 48, 49, 49, 48, 5, 48, 6,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 10, 48, 12, 48, 14, 15,
- 16, 17, 18, 48, 48, 48, 21, 48,
- 2, 48, 49, 49, 48, 5, 48, 6,
- 48, 48, 48, 48, 48, 48, 48, 57,
- 48, 48, 10, 48, 48, 48, 14, 15,
- 16, 17, 18, 48, 48, 48, 21, 48,
- 2, 48, 49, 49, 48, 5, 48, 6,
- 48, 48, 48, 48, 48, 48, 48, 58,
- 48, 48, 10, 11, 12, 48, 14, 15,
- 16, 17, 18, 48, 48, 48, 21, 48,
- 2, 48, 49, 49, 48, 5, 48, 6,
- 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 10, 11, 12, 48, 14, 15,
- 16, 17, 18, 48, 48, 48, 21, 48,
- 2, 3, 49, 49, 48, 5, 48, 6,
- 48, 48, 48, 48, 48, 48, 48, 8,
- 48, 48, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 48, 48, 48, 21, 48,
- 23, 24, 25, 25, 22, 26, 22, 27,
- 22, 22, 22, 22, 22, 22, 22, 59,
- 22, 22, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 22, 22, 39, 22,
- 23, 60, 25, 25, 22, 26, 22, 27,
- 22, 22, 22, 22, 22, 22, 22, 28,
- 22, 22, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 22, 22, 22, 39, 22,
- 1, 1, 2, 3, 49, 49, 48, 5,
- 48, 6, 1, 48, 48, 48, 48, 1,
- 48, 8, 48, 48, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 48, 1,
- 21, 48, 1, 1, 61, 61, 61, 61,
- 61, 61, 61, 61, 1, 61, 61, 61,
- 61, 1, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 1, 61, 62, 61, 0
-};
-
-static const char _myanmar_syllable_machine_trans_targs[] = {
- 0, 1, 26, 37, 0, 27, 33, 51,
- 39, 54, 40, 46, 47, 48, 29, 42,
- 43, 44, 32, 50, 55, 45, 0, 2,
- 13, 0, 3, 9, 14, 15, 21, 22,
- 23, 5, 17, 18, 19, 8, 25, 20,
- 4, 6, 7, 10, 12, 11, 16, 24,
- 0, 0, 28, 30, 31, 34, 36, 35,
- 38, 41, 49, 52, 53, 0, 0
-};
-
-static const char _myanmar_syllable_machine_trans_actions[] = {
- 3, 0, 0, 0, 4, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 5, 0,
- 0, 6, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 7, 8, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 9, 10
-};
-
-static const char _myanmar_syllable_machine_to_state_actions[] = {
- 1, 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 _myanmar_syllable_machine_from_state_actions[] = {
- 2, 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 _myanmar_syllable_machine_eof_trans[] = {
- 0, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 23, 23, 49, 62, 62
-};
-
-static const int myanmar_syllable_machine_start = 0;
-static const int myanmar_syllable_machine_first_final = 0;
-static const int myanmar_syllable_machine_error = -1;
-
-static const int myanmar_syllable_machine_en_main = 0;
-
-
-#line 44 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
-
-#line 102 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-static void
-find_syllables_myanmar (hb_buffer_t *buffer)
-{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 382 "hb-ot-shape-complex-myanmar-machine.hh"
- {
- cs = myanmar_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
-
-#line 398 "hb-ot-shape-complex-myanmar-machine.hh"
- {
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
- case 2:
-#line 1 "NONE"
- {ts = p;}
- break;
-#line 412 "hb-ot-shape-complex-myanmar-machine.hh"
- }
-
- _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
- _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
-
- _slen = _myanmar_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
- ( info[p].myanmar_category()) <= _keys[1] ?
- ( info[p].myanmar_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _myanmar_syllable_machine_trans_targs[_trans];
-
- if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
- case 6:
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
- break;
- case 4:
-#line 95 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
- break;
- case 10:
-#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (myanmar_punctuation_cluster); }}
- break;
- case 8:
-#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (myanmar_broken_cluster); }}
- break;
- case 3:
-#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
- break;
- case 5:
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
- break;
- case 7:
-#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (myanmar_broken_cluster); }}
- break;
- case 9:
-#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
- break;
-#line 462 "hb-ot-shape-complex-myanmar-machine.hh"
- }
-
-_again:
- switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
- case 1:
-#line 1 "NONE"
- {ts = 0;}
- break;
-#line 471 "hb-ot-shape-complex-myanmar-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 130 "hb-ot-shape-complex-myanmar-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
deleted file mode 100644
index 7fbca3878f..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright © 2018 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-indic.hh"
-
-
-/* buffer var allocations */
-#define myanmar_category() indic_category() /* myanmar_category_t */
-#define myanmar_position() indic_position() /* myanmar_position_t */
-
-
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum myanmar_category_t {
- OT_As = 18, /* Asat */
- OT_D0 = 20, /* Digit zero */
- OT_DB = OT_N, /* Dot below */
- OT_GB = OT_PLACEHOLDER,
- OT_MH = 21, /* Various consonant medial types */
- OT_MR = 22, /* Various consonant medial types */
- OT_MW = 23, /* Various consonant medial types */
- OT_MY = 24, /* Various consonant medial types */
- OT_PT = 25, /* Pwo and other tones */
- //OT_VAbv = 26,
- //OT_VBlw = 27,
- //OT_VPre = 28,
- //OT_VPst = 29,
- OT_VS = 30, /* Variation selectors */
- OT_P = 31, /* Punctuation */
- OT_D = 32, /* Digits except zero */
- OT_ML = 33, /* Various consonant medial types */
-};
-
-using myanmar_position_t = indic_position_t;
-
-static inline void
-set_myanmar_properties (hb_glyph_info_t &info)
-{
- hb_codepoint_t u = info.codepoint;
- unsigned int type = hb_indic_get_categories (u);
- unsigned int cat = type & 0xFFu;
- myanmar_position_t pos = (myanmar_position_t) (type >> 8);
-
- /* Myanmar
- * https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze
- */
- if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)))
- cat = OT_VS;
-
- switch (u)
- {
- case 0x104Eu:
- cat = OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
- break;
-
- case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
- case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
- case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
- case 0x25FEu:
- cat = OT_GB;
- break;
-
- case 0x1004u: case 0x101Bu: case 0x105Au:
- cat = OT_Ra;
- break;
-
- case 0x1032u: case 0x1036u:
- cat = OT_A;
- break;
-
- case 0x1039u:
- cat = OT_H;
- break;
-
- case 0x103Au:
- cat = OT_As;
- break;
-
- case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
- case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
- case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
- case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
- case 0x1097u: case 0x1098u: case 0x1099u:
- cat = OT_D;
- break;
-
- case 0x1040u:
- cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
- break;
-
- case 0x103Eu:
- cat = OT_MH;
- break;
-
- case 0x1060u:
- cat = OT_ML;
- break;
-
- case 0x103Cu:
- cat = OT_MR;
- break;
-
- case 0x103Du: case 0x1082u:
- cat = OT_MW;
- break;
-
- case 0x103Bu: case 0x105Eu: case 0x105Fu:
- cat = OT_MY;
- break;
-
- case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
- case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
- cat = OT_PT;
- break;
-
- case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
- case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
- case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
- cat = OT_SM;
- break;
-
- case 0x104Au: case 0x104Bu:
- cat = OT_P;
- break;
-
- case 0xAA74u: case 0xAA75u: case 0xAA76u:
- /* https://github.com/harfbuzz/harfbuzz/issues/218 */
- cat = OT_C;
- break;
- }
-
- if (cat == OT_M)
- {
- switch ((int) pos)
- {
- case POS_PRE_C: cat = (myanmar_category_t) OT_VPre;
- pos = POS_PRE_M; break;
- case POS_ABOVE_C: cat = (myanmar_category_t) OT_VAbv; break;
- case POS_BELOW_C: cat = (myanmar_category_t) OT_VBlw; break;
- case POS_POST_C: cat = (myanmar_category_t) OT_VPst; break;
- }
- }
-
- info.myanmar_category() = cat;
- info.myanmar_position() = pos;
-}
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
deleted file mode 100644
index 468bd95c3f..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
+++ /dev/null
@@ -1,849 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-use-machine.rl"
-/*
- * Copyright © 2015 Mozilla Foundation.
- * Copyright © 2015 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.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-syllabic.hh"
-
-/* buffer var allocations */
-#define use_category() complex_var_u8_category()
-
-#define USE(Cat) use_syllable_machine_ex_##Cat
-
-enum use_syllable_type_t {
- use_virama_terminated_cluster,
- use_sakot_terminated_cluster,
- use_standard_cluster,
- use_number_joiner_terminated_cluster,
- use_numeral_cluster,
- use_symbol_cluster,
- use_hieroglyph_cluster,
- use_broken_cluster,
- use_non_cluster,
-};
-
-
-#line 57 "hb-ot-shape-complex-use-machine.hh"
-#define use_syllable_machine_ex_B 1u
-#define use_syllable_machine_ex_CGJ 6u
-#define use_syllable_machine_ex_CMAbv 31u
-#define use_syllable_machine_ex_CMBlw 32u
-#define use_syllable_machine_ex_CS 43u
-#define use_syllable_machine_ex_FAbv 24u
-#define use_syllable_machine_ex_FBlw 25u
-#define use_syllable_machine_ex_FMAbv 45u
-#define use_syllable_machine_ex_FMBlw 46u
-#define use_syllable_machine_ex_FMPst 47u
-#define use_syllable_machine_ex_FPst 26u
-#define use_syllable_machine_ex_G 49u
-#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_IS 44u
-#define use_syllable_machine_ex_J 50u
-#define use_syllable_machine_ex_MAbv 27u
-#define use_syllable_machine_ex_MBlw 28u
-#define use_syllable_machine_ex_MPre 30u
-#define use_syllable_machine_ex_MPst 29u
-#define use_syllable_machine_ex_N 4u
-#define use_syllable_machine_ex_O 0u
-#define use_syllable_machine_ex_R 18u
-#define use_syllable_machine_ex_SB 51u
-#define use_syllable_machine_ex_SE 52u
-#define use_syllable_machine_ex_SMAbv 41u
-#define use_syllable_machine_ex_SMBlw 42u
-#define use_syllable_machine_ex_SUB 11u
-#define use_syllable_machine_ex_Sk 48u
-#define use_syllable_machine_ex_VAbv 33u
-#define use_syllable_machine_ex_VBlw 34u
-#define use_syllable_machine_ex_VMAbv 37u
-#define use_syllable_machine_ex_VMBlw 38u
-#define use_syllable_machine_ex_VMPre 23u
-#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 100 "hb-ot-shape-complex-use-machine.hh"
-static const unsigned char _use_syllable_machine_trans_keys[] = {
- 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, 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, 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, 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, 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, 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, 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, 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, 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[] = {
- 1, 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, 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[] = {
- 2, 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, 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, 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;
-static const int use_syllable_machine_first_final = 0;
-static const int use_syllable_machine_error = -1;
-
-static const int use_syllable_machine_en_main = 0;
-
-
-#line 58 "hb-ot-shape-complex-use-machine.rl"
-
-
-
-#line 181 "hb-ot-shape-complex-use-machine.rl"
-
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
- for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-
-template <typename Iter>
-struct machine_index_t :
- hb_iter_with_fallback_t<machine_index_t<Iter>,
- typename Iter::item_t>
-{
- machine_index_t (const Iter& it) : it (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;
-
- typename Iter::item_t __item__ () const { return *it; }
- typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
- unsigned __len__ () const { return it.len (); }
- void __next__ () { ++it; }
- void __forward__ (unsigned n) { it += n; }
- void __prev__ () { --it; }
- void __rewind__ (unsigned n) { it -= n; }
-
- void operator = (unsigned n)
- {
- 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
-{
- template <typename Iter,
- hb_requires (hb_is_iterable (Iter))>
- machine_index_t<hb_iter_type<Iter>>
- operator () (Iter&& it) const
- { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
-}
-HB_FUNCOBJ (machine_index);
-
-
-
-static bool
-not_ccs_default_ignorable (const hb_glyph_info_t &i)
-{ return i.use_category() != USE(CGJ); }
-
-static inline void
-find_syllables_use (hb_buffer_t *buffer)
-{
- hb_glyph_info_t *info = buffer->info;
- auto p =
- + hb_iter (info, buffer->len)
- | hb_enumerate
- | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
- hb_second)
- | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
- {
- if (p.second.use_category() == USE(ZWNJ))
- for (unsigned i = p.first + 1; i < buffer->len; ++i)
- if (not_ccs_default_ignorable (info[i]))
- return !_hb_glyph_info_is_unicode_mark (&info[i]);
- return true;
- })
- | hb_enumerate
- | machine_index
- ;
- auto pe = p + p.len ();
- auto eof = +pe;
- auto ts = +p;
- auto te = +p;
- unsigned int act HB_UNUSED;
- int cs;
-
-#line 702 "hb-ot-shape-complex-use-machine.hh"
- {
- cs = use_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 281 "hb-ot-shape-complex-use-machine.rl"
-
-
- unsigned int syllable_serial = 1;
-
-#line 715 "hb-ot-shape-complex-use-machine.hh"
- {
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _use_syllable_machine_from_state_actions[cs] ) {
- case 2:
-#line 1 "NONE"
- {ts = p;}
- break;
-#line 729 "hb-ot-shape-complex-use-machine.hh"
- }
-
- _keys = _use_syllable_machine_trans_keys + (cs<<1);
- _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
-
- _slen = _use_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
- ( (*p).second.second.use_category()) <= _keys[1] ?
- ( (*p).second.second.use_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _use_syllable_machine_trans_targs[_trans];
-
- if ( _use_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _use_syllable_machine_trans_actions[_trans] ) {
- case 9:
-#line 171 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (use_standard_cluster); }}
- break;
- 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 177 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (use_non_cluster); }}
- break;
- case 11:
-#line 170 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
- break;
- case 7:
-#line 171 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_standard_cluster); }}
- break;
- case 14:
-#line 172 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
- break;
- case 13:
-#line 173 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_numeral_cluster); }}
- break;
- case 5:
-#line 174 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_symbol_cluster); }}
- break;
- case 17:
-#line 175 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
- break;
- case 15:
-#line 176 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_broken_cluster); }}
- break;
- case 16:
-#line 177 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_non_cluster); }}
- break;
- 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:
- switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 1:
-#line 1 "NONE"
- {ts = 0;}
- break;
-#line 828 "hb-ot-shape-complex-use-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _use_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 286 "hb-ot-shape-complex-use-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
index aa5a8eeaa3..7db0b25b73 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -29,7 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-normalize.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
#include "hb-ot-shape.hh"
@@ -69,7 +69,7 @@
* - When a font does not support a character but supports its canonical
* decomposition, well, use the decomposition.
*
- * - The complex shapers can customize the compose and decompose functions to
+ * - The shapers can customize the compose and decompose functions to
* offload some of their requirements to the normalizer. For example, the
* Indic shaper may want to disallow recomposing of two matras.
*/
@@ -143,8 +143,7 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint
return 1;
}
- unsigned int ret;
- if ((ret = decompose (c, shortest, a))) {
+ if (unsigned ret = decompose (c, shortest, a)) {
if (b) {
output_char (buffer, b, b_glyph);
return ret + 1;
@@ -223,7 +222,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
unsigned int end,
bool short_circuit HB_UNUSED)
{
- /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+ /* Currently if there's a variation-selector we give-up on normalization, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1 && buffer->successful;) {
@@ -395,7 +394,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
break;
/* We are going to do a O(n^2). Only do this if the sequence is short. */
- if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
+ if (end - i > HB_OT_SHAPE_MAX_COMBINING_MARKS) {
i = end;
continue;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 298cf47786..0806abb7dd 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -37,7 +37,7 @@
#include "hb-shaper-impl.hh"
#include "hb-ot-shape.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
#include "hb-ot-shape-fallback.hh"
#include "hb-ot-shape-normalize.hh"
@@ -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
@@ -83,14 +86,14 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac
, apply_morx (_hb_apply_morx (face, props))
#endif
{
- shaper = hb_ot_shape_complex_categorize (this);
+ shaper = hb_ot_shaper_categorize (this);
script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
script_fallback_mark_positioning = shaper->fallback_position;
/* https://github.com/harfbuzz/harfbuzz/issues/1528 */
- if (apply_morx && shaper != &_hb_ot_complex_shaper_default)
- shaper = &_hb_ot_complex_shaper_dumber;
+ if (apply_morx && shaper != &_hb_ot_shaper_default)
+ shaper = &_hb_ot_shaper_dumber;
}
void
@@ -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]);
}
@@ -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;
}
@@ -915,7 +927,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
+hb_ot_substitute_plan (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -934,7 +946,7 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
_hb_buffer_allocate_gsubgpos_vars (c->buffer);
- hb_ot_substitute_complex (c);
+ hb_ot_substitute_plan (c);
#ifndef HB_NO_AAT_SHAPE
if (c->plan->apply_morx && c->plan->apply_gpos)
@@ -1027,7 +1039,7 @@ hb_ot_position_default (const hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_position_complex (const hb_ot_shape_context_t *c)
+hb_ot_position_plan (const hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
@@ -1112,7 +1124,7 @@ hb_ot_position (const hb_ot_shape_context_t *c)
hb_ot_position_default (c);
- hb_ot_position_complex (c);
+ hb_ot_position_plan (c);
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
hb_buffer_reverse (c->buffer);
@@ -1147,8 +1159,6 @@ hb_propagate_flags (hb_buffer_t *buffer)
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
- c->buffer->enter ();
-
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.hh b/thirdparty/harfbuzz/src/hb-ot-shape.hh
index e8c81015c7..17fa58b337 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.hh
@@ -61,7 +61,7 @@ struct hb_shape_plan_key_t;
struct hb_ot_shape_plan_t
{
hb_segment_properties_t props;
- const struct hb_ot_complex_shaper_t *shaper;
+ const struct hb_ot_shaper_t *shaper;
hb_ot_map_t map;
hb_aat_map_t aat_map;
const void *data;
@@ -158,7 +158,7 @@ struct hb_ot_shape_planner_t
#endif
bool script_zero_marks : 1;
bool script_fallback_mark_positioning : 1;
- const struct hb_ot_complex_shaper_t *shaper;
+ const struct hb_ot_shaper_t *shaper;
HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face,
const hb_segment_properties_t *props);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh
index 78f46c1cac..b9f92f72d6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh
@@ -24,8 +24,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+#ifndef HB_OT_SHAPER_ARABIC_FALLBACK_HH
+#define HB_OT_SHAPER_ARABIC_FALLBACK_HH
#include "hb.hh"
@@ -34,7 +34,11 @@
/* Features ordered the same as the entries in shaping_table rows,
- * followed by rlig. Don't change. */
+ * followed by rlig. Don't change.
+ *
+ * We currently support one subtable per lookup, and one lookup
+ * per feature. But we allow duplicate features, so we use that!
+ */
static const hb_tag_t arabic_fallback_features[] =
{
HB_TAG('i','n','i','t'),
@@ -42,6 +46,8 @@ static const hb_tag_t arabic_fallback_features[] =
HB_TAG('f','i','n','a'),
HB_TAG('i','s','o','l'),
HB_TAG('r','l','i','g'),
+ HB_TAG('r','l','i','g'),
+ HB_TAG('r','l','i','g'),
};
static OT::SubstLookup *
@@ -95,20 +101,25 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
}
+template <typename T>
static OT::SubstLookup *
arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font)
+ hb_font_t *font,
+ const T &ligature_table,
+ unsigned lookup_flags)
{
OT::HBGlyphID16 first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
unsigned int num_first_glyphs = 0;
- /* We know that all our ligatures are 2-component */
+ /* We know that all our ligatures have the same number of components. */
OT::HBGlyphID16 ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
- OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+ OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) *
+ ARRAY_LENGTH_CONST (ligature_table[0].ligatures[0].components)];
unsigned int num_ligatures = 0;
+ unsigned int num_components = 0;
/* Populate arrays */
@@ -133,21 +144,32 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
{
unsigned int first_glyph_idx = first_glyphs_indirection[i];
- for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
+ for (unsigned int ligature_idx = 0; ligature_idx < ARRAY_LENGTH (ligature_table[0].ligatures); ligature_idx++)
{
- hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
- hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
- hb_codepoint_t second_glyph, ligature_glyph;
- if (!second_u ||
- !hb_font_get_glyph (font, second_u, 0, &second_glyph) ||
- !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
+ hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].ligature;
+ hb_codepoint_t ligature_glyph;
+ if (!hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
continue;
- ligature_per_first_glyph_count_list[i]++;
+ const auto &components = ligature_table[first_glyph_idx].ligatures[ligature_idx].components;
+ unsigned component_count = ARRAY_LENGTH_CONST (components);
+
+ for (unsigned i = 0; i < component_count; i++)
+ {
+ hb_codepoint_t component_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].components[i];
+ hb_codepoint_t component_glyph;
+ if (!component_u ||
+ !hb_font_get_glyph (font, component_u, 0, &component_glyph))
+ continue;
+ component_list[num_components++] = component_glyph;
+ }
+
+ component_count_list[num_ligatures] = 1 + component_count;
ligature_list[num_ligatures] = ligature_glyph;
- component_count_list[num_ligatures] = 2;
- component_list[num_ligatures] = second_glyph;
+
+ ligature_per_first_glyph_count_list[i]++;
+
num_ligatures++;
}
}
@@ -161,14 +183,13 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
hb_serialize_context_t c (buf, sizeof (buf));
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
bool ret = lookup->serialize_ligature (&c,
- OT::LookupFlag::IgnoreMarks,
+ lookup_flags,
hb_sorted_array (first_glyphs, num_first_glyphs),
hb_array (ligature_per_first_glyph_count_list, num_first_glyphs),
hb_array (ligature_list, num_ligatures),
hb_array (component_count_list, num_ligatures),
- hb_array (component_list, num_ligatures));
+ hb_array (component_list, num_components));
c.end_serialize ();
- /* TODO sanitize the results? */
return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
}
@@ -181,10 +202,18 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
if (feature_index < 4)
return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
else
- return arabic_fallback_synthesize_lookup_ligature (plan, font);
+ {
+ switch (feature_index) {
+ case 4: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_3_table, OT::LookupFlag::IgnoreMarks);
+ case 5: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_table, OT::LookupFlag::IgnoreMarks);
+ case 6: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_mark_table, 0);
+ }
+ }
+ assert (false);
+ return nullptr;
}
-#define ARABIC_FALLBACK_MAX_LOOKUPS 5
+#define ARABIC_FALLBACK_MAX_LOOKUPS ARRAY_LENGTH_CONST (arabic_fallback_features)
struct arabic_fallback_plan_t
{
@@ -201,7 +230,7 @@ struct arabic_fallback_plan_t
#endif
#ifdef HB_WITH_WIN1256
-#include "hb-ot-shape-complex-arabic-win1256.hh"
+#include "hb-ot-shaper-arabic-win1256.hh"
#endif
struct ManifestLookup
@@ -230,9 +259,8 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS
return false;
const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
- static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) ==
+ static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) <=
ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), "");
- /* TODO sanitize the table? */
unsigned j = 0;
unsigned int count = manifest.len;
@@ -264,7 +292,7 @@ arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
- static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
+ static_assert ((ARRAY_LENGTH_CONST (arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
unsigned int j = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
{
@@ -345,4 +373,4 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
}
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
+#endif /* HB_OT_SHAPER_ARABIC_FALLBACK_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
index e6339ee72b..a5ce3a6c93 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
@@ -12,8 +12,8 @@
* # Date: 2021-07-10, 00:35:31 GMT
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
+#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
static bool
has_arabic_joining (hb_script_t script)
@@ -42,6 +42,6 @@ has_arabic_joining (hb_script_t script)
}
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */
+#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */
/* == End of generated function == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh
new file mode 100644
index 0000000000..ba86772f84
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh
@@ -0,0 +1,118 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ * ./gen-arabic-pua.py
+ *
+ */
+
+#ifndef HB_OT_SHAPER_ARABIC_PUA_HH
+#define HB_OT_SHAPER_ARABIC_PUA_HH
+
+static const uint8_t
+_hb_arabic_u8[464] =
+{
+ 84, 86, 85, 85, 85, 85, 85,213, 16, 34, 34, 34, 34, 34, 35, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 36, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 82, 16, 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 7,
+ 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 0, 0, 0, 22, 0, 23, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 16, 34, 34, 34, 35, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 66, 16, 50, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68,101, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,152,186, 76, 77, 68,254, 16, 50,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 5, 6,
+ 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 13, 0, 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 23, 23, 29, 30, 31, 32, 33, 0, 0, 0, 0,
+ 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 36, 37, 38, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 40,
+ 41, 42, 0, 43, 44, 0, 0, 45, 46, 0, 47, 48, 49, 0, 0, 0,
+ 0, 50, 0, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 0, 0, 0,
+ 0, 0, 59, 60, 61, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 66,
+ 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+};
+static const uint16_t
+_hb_arabic_u16[720] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,61728,61729,61730, 0, 0,61733, 0, 0,
+ 61736,61737,61738,61739,61790,61741,61742,61743,61872,61873,61874,61875,61876,61877,61878,61879,
+ 61880,61881,61754,61755, 0,61757, 0,61759, 0, 0, 0,61787,61788,61789, 0, 0,
+ 0, 0, 0,61731, 0, 0, 0, 0, 0, 0, 0,61732, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,61734, 0, 0, 0, 0, 0, 0, 0,61735,
+ 0, 0, 0, 0,61740, 0, 0, 0, 0, 0, 0,61755, 0, 0, 0,61759,
+ 0,61869,61765,61763,61883,61767,61882,61761,61770,61865,61772,61774,61777,61780,61783,61784,
+ 61785,61786,61792,61794,61796,61798,61800,61801,61802,61806,61810,61696,61696,61696,61696,61696,
+ 61791,61813,61816,61818,61820,61822,61921,61860,61861,61868,61864,61895,61896,61899,61892,61893,
+ 61898,61897,61894,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696, 0,
+ 61744,61745,61746,61747,61748,61749,61750,61751,61752,61753, 0,61790,61790, 0, 0, 0,
+ 0, 0, 0, 0,61708,61709,61710,61711,61756,61758, 0, 0, 0, 0, 0, 0,
+ 0,61765,61766,61763,61764,61883,61883,61767,61768,61882,61871,61870,61870,61761,61762,61770,
+ 61770,61769,61769,61865,61866,61772,61772,61771,61771,61774,61774,61773,61773,61777,61776,61775,
+ 61775,61780,61779,61778,61778,61783,61782,61781,61781,61784,61784,61785,61785,61786,61786,61792,
+ 61792,61794,61794,61793,61793,61796,61796,61795,61795,61798,61798,61797,61797,61800,61800,61799,
+ 61799,61801,61801,61801,61801,61802,61802,61802,61802,61806,61805,61803,61804,61810,61809,61807,
+ 61808,61813,61813,61811,61812,61816,61816,61814,61815,61818,61818,61817,61817,61820,61820,61819,
+ 61819,61822,61822,61821,61821,61921,61921,61823,61823,61860,61859,61857,61858,61861,61861,61868,
+ 61867,61864,61863,61862,61862,61888,61889,61886,61887,61890,61891,61885,61884, 0, 0, 0,
+ 0, 0, 0, 0,61984,61985,61986, 0, 0,61989, 0, 0,61992,61993,61994,61995,
+ 62046,61997,61998,61999, 0, 0,62010,62011, 0,62013, 0,62015, 0, 0, 0,62043,
+ 0,62045, 0, 0, 0, 0, 0,61987, 0, 0, 0,61988, 0, 0, 0,61990,
+ 0, 0, 0,61991,61996, 0, 0, 0, 0, 0, 0,62011, 0, 0, 0,62015,
+ 0,62165,62021,62019,62170,62023,62169,62017,62028,62161,62032,62036,62040,62048,62052,62053,
+ 62055,62057,62059,62064,62068,62072,62078,62114,62115,62122,62126,61952,61952,61952,61952,61952,
+ 62047,62130,62134,62138,62142,62146,62150,62154,62155,62164,62160,62183,62184,62187,62180,62181,
+ 62186,62185,62182,61952,61952,61952,61952, 0,62000,62001,62002,62003,62004,62005,62006,62007,
+ 62008,62009, 0,62046,62046, 0, 0, 0,61964,61965,61966,61967,62012,62014, 0, 0,
+ 61954, 0,61981, 0, 0, 0,61955, 0,61982, 0,61956, 0, 0, 0,62111, 0,
+ 0, 0, 0,61970,61971,61972,61957, 0,61980, 0, 0, 0, 0, 0,61958, 0,
+ 61983, 0, 0, 0, 0, 0,62191, 0,62188,62189,62192, 0, 0, 0,61973, 0,
+ 0,62098, 0, 0,61974, 0, 0,62099, 0, 0,62101, 0, 0,61975, 0, 0,
+ 62100, 0, 0, 0,62080,62081,62082,62102, 0,62083,62084,62085,62103, 0, 0, 0,
+ 62106, 0,62107, 0,62108, 0, 0, 0,61976, 0, 0, 0, 0,62086,62087,62088,
+ 62109,61978,62089,62090,62091,62110,62093,62094, 0,62104, 0, 0, 0, 0,62095,62096,
+ 62097,62105, 0, 0,61977, 0, 0, 0, 0, 0,62075,62077,61968, 0, 0, 0,
+ 0,62021,62022,62019,62020,62170,62171,62023,62024,62169,62168,62166,62167,62017,62018,62028,
+ 62027,62025,62026,62161,62162,62032,62031,62029,62030,62036,62035,62033,62034,62040,62039,62037,
+ 62038,62048,62044,62041,62042,62052,62051,62049,62050,62053,62054,62055,62056,62057,62058,62059,
+ 62060,62064,62063,62061,62062,62068,62067,62065,62066,62072,62071,62069,62070,62078,62076,62073,
+ 62074,62114,62113,62079,62193,62118,62117,62115,62116,62122,62121,62119,62120,62126,62125,62123,
+ 62124,62130,62129,62127,62128,62134,62133,62131,62132,62138,62137,62135,62136,62142,62141,62139,
+ 62140,62146,62145,62143,62144,62150,62149,62147,62148,62154,62153,62151,62152,62155,62156,62164,
+ 62163,62160,62159,62157,62158,62176,62177,62174,62175,62178,62179,62172,62173, 0, 0, 0,
+};
+
+static inline unsigned
+_hb_arabic_b2 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>2]>>((i&3u)<<1))&3u;
+}
+static inline unsigned
+_hb_arabic_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast16_t
+_hb_arabic_pua_simp_map (unsigned u)
+{
+ return u<65277u?_hb_arabic_u16[((_hb_arabic_u8[40+(((_hb_arabic_b4(8+_hb_arabic_u8,((_hb_arabic_b2(_hb_arabic_u8,u>>3>>4>>4))<<4)+((u>>3>>4)&15u)))<<4)+((u>>3)&15u))])<<3)+((u)&7u)]:0;
+}
+static inline uint_fast16_t
+_hb_arabic_pua_trad_map (unsigned u)
+{
+ return u<65277u?_hb_arabic_u16[320+(((_hb_arabic_u8[208+(((_hb_arabic_b4(168+_hb_arabic_u8,((_hb_arabic_b4(136+_hb_arabic_u8,u>>2>>4>>4))<<4)+((u>>2>>4)&15u)))<<4)+((u>>2)&15u))])<<2)+((u)&3u))]:0;
+}
+
+#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */
+
+/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
index c158964f2c..fd3d8645d1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
@@ -13,8 +13,8 @@
* UnicodeData.txt does not have a header.
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
+#ifndef HB_OT_SHAPER_ARABIC_TABLE_HH
+#define HB_OT_SHAPER_ARABIC_TABLE_HH
#define A JOINING_GROUP_ALAPH
@@ -416,26 +416,141 @@ static const uint16_t shaping_table[][4] =
static const struct ligature_set_t {
uint16_t first;
struct ligature_pairs_t {
- uint16_t second;
+ uint16_t components[1];
uint16_t ligature;
- } ligatures[4];
+ } ligatures[14];
} ligature_table[] =
{
+ { 0xFE91u, {
+ { {0xFEE2u}, 0xFC08u }, /* ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM */
+ { {0xFEE4u}, 0xFC9Fu }, /* ARABIC LIGATURE BEH WITH MEEM INITIAL FORM */
+ { {0xFEA0u}, 0xFC9Cu }, /* ARABIC LIGATURE BEH WITH JEEM INITIAL FORM */
+ { {0xFEA4u}, 0xFC9Du }, /* ARABIC LIGATURE BEH WITH HAH INITIAL FORM */
+ { {0xFEA8u}, 0xFC9Eu }, /* ARABIC LIGATURE BEH WITH KHAH INITIAL FORM */
+ }},
+ { 0xFE92u, {
+ { {0xFEAEu}, 0xFC6Au }, /* ARABIC LIGATURE BEH WITH REH FINAL FORM */
+ { {0xFEE6u}, 0xFC6Du }, /* ARABIC LIGATURE BEH WITH NOON FINAL FORM */
+ { {0xFEF2u}, 0xFC6Fu }, /* ARABIC LIGATURE BEH WITH YEH FINAL FORM */
+ }},
+ { 0xFE97u, {
+ { {0xFEE2u}, 0xFC0Eu }, /* ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM */
+ { {0xFEE4u}, 0xFCA4u }, /* ARABIC LIGATURE TEH WITH MEEM INITIAL FORM */
+ { {0xFEA0u}, 0xFCA1u }, /* ARABIC LIGATURE TEH WITH JEEM INITIAL FORM */
+ { {0xFEA4u}, 0xFCA2u }, /* ARABIC LIGATURE TEH WITH HAH INITIAL FORM */
+ { {0xFEA8u}, 0xFCA3u }, /* ARABIC LIGATURE TEH WITH KHAH INITIAL FORM */
+ }},
+ { 0xFE98u, {
+ { {0xFEAEu}, 0xFC70u }, /* ARABIC LIGATURE TEH WITH REH FINAL FORM */
+ { {0xFEE6u}, 0xFC73u }, /* ARABIC LIGATURE TEH WITH NOON FINAL FORM */
+ { {0xFEF2u}, 0xFC75u }, /* ARABIC LIGATURE TEH WITH YEH FINAL FORM */
+ }},
+ { 0xFE9Bu, {
+ { {0xFEE2u}, 0xFC12u }, /* ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM */
+ }},
+ { 0xFE9Fu, {
+ { {0xFEE4u}, 0xFCA8u }, /* ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEA3u, {
+ { {0xFEE4u}, 0xFCAAu }, /* ARABIC LIGATURE HAH WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEA7u, {
+ { {0xFEE4u}, 0xFCACu }, /* ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEB3u, {
+ { {0xFEE4u}, 0xFCB0u }, /* ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEB7u, {
+ { {0xFEE4u}, 0xFD30u }, /* ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM */
+ }},
+ { 0xFED3u, {
+ { {0xFEF2u}, 0xFC32u }, /* ARABIC LIGATURE FEH WITH YEH ISOLATED FORM */
+ }},
{ 0xFEDFu, {
- { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
- { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
- { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
- { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+ { {0xFE9Eu}, 0xFC3Fu }, /* ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM */
+ { {0xFEA0u}, 0xFCC9u }, /* ARABIC LIGATURE LAM WITH JEEM INITIAL FORM */
+ { {0xFEA2u}, 0xFC40u }, /* ARABIC LIGATURE LAM WITH HAH ISOLATED FORM */
+ { {0xFEA4u}, 0xFCCAu }, /* ARABIC LIGATURE LAM WITH HAH INITIAL FORM */
+ { {0xFEA6u}, 0xFC41u }, /* ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM */
+ { {0xFEA8u}, 0xFCCBu }, /* ARABIC LIGATURE LAM WITH KHAH INITIAL FORM */
+ { {0xFEE2u}, 0xFC42u }, /* ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM */
+ { {0xFEE4u}, 0xFCCCu }, /* ARABIC LIGATURE LAM WITH MEEM INITIAL FORM */
+ { {0xFEF2u}, 0xFC44u }, /* ARABIC LIGATURE LAM WITH YEH ISOLATED FORM */
+ { {0xFEECu}, 0xFCCDu }, /* ARABIC LIGATURE LAM WITH HEH INITIAL FORM */
+ { {0xFE82u}, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+ { {0xFE84u}, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+ { {0xFE88u}, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+ { {0xFE8Eu}, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
}},
{ 0xFEE0u, {
- { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
- { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
- { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
- { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+ { {0xFEF0u}, 0xFC86u }, /* ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM */
+ { {0xFE82u}, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+ { {0xFE84u}, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+ { {0xFE88u}, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+ { {0xFE8Eu}, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+ }},
+ { 0xFEE3u, {
+ { {0xFEA0u}, 0xFCCEu }, /* ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM */
+ { {0xFEA4u}, 0xFCCFu }, /* ARABIC LIGATURE MEEM WITH HAH INITIAL FORM */
+ { {0xFEA8u}, 0xFCD0u }, /* ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM */
+ { {0xFEE4u}, 0xFCD1u }, /* ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEE7u, {
+ { {0xFEE2u}, 0xFC4Eu }, /* ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM */
+ { {0xFEE4u}, 0xFCD5u }, /* ARABIC LIGATURE NOON WITH MEEM INITIAL FORM */
+ { {0xFEA0u}, 0xFCD2u }, /* ARABIC LIGATURE NOON WITH JEEM INITIAL FORM */
+ { {0xFEA4u}, 0xFCD3u }, /* ARABIC LIGATURE NOON WITH HAH INITIAL FORM */
+ }},
+ { 0xFEE8u, {
+ { {0xFEF2u}, 0xFC8Fu }, /* ARABIC LIGATURE NOON WITH YEH FINAL FORM */
+ }},
+ { 0xFEF3u, {
+ { {0xFEA0u}, 0xFCDAu }, /* ARABIC LIGATURE YEH WITH JEEM INITIAL FORM */
+ { {0xFEA4u}, 0xFCDBu }, /* ARABIC LIGATURE YEH WITH HAH INITIAL FORM */
+ { {0xFEA8u}, 0xFCDCu }, /* ARABIC LIGATURE YEH WITH KHAH INITIAL FORM */
+ { {0xFEE4u}, 0xFCDDu }, /* ARABIC LIGATURE YEH WITH MEEM INITIAL FORM */
+ }},
+ { 0xFEF4u, {
+ { {0xFEAEu}, 0xFC91u }, /* ARABIC LIGATURE YEH WITH REH FINAL FORM */
+ { {0xFEE6u}, 0xFC94u }, /* ARABIC LIGATURE YEH WITH NOON FINAL FORM */
+ }},
+};
+
+
+static const struct ligature_mark_set_t {
+ uint16_t first;
+ struct ligature_pairs_t {
+ uint16_t components[1];
+ uint16_t ligature;
+ } ligatures[5];
+} ligature_mark_table[] =
+{
+ { 0x0651u, {
+ { {0x064Cu}, 0xFC5Eu }, /* ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM */
+ { {0x064Eu}, 0xFC60u }, /* ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM */
+ { {0x064Fu}, 0xFC61u }, /* ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM */
+ { {0x0650u}, 0xFC62u }, /* ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM */
+ { {0x064Bu}, 0xF2EEu }, /* PUA ARABIC LIGATURE SHADDA WITH FATHATAN ISOLATED FORM */
+ }},
+};
+
+
+static const struct ligature_3_set_t {
+ uint16_t first;
+ struct ligature_triplets_t {
+ uint16_t components[2];
+ uint16_t ligature;
+ } ligatures[3];
+} ligature_3_table[] =
+{
+ { 0xFEDFu, {
+ { {0xFEE4u, 0xFEA4u}, 0xFD88u}, /* ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM */
+ { {0xFEE0u, 0xFEEAu}, 0xF201u}, /* PUA ARABIC LIGATURE LELLAH ISOLATED FORM */
+ { {0xFEE4u, 0xFEA0u}, 0xF211u}, /* PUA ARABIC LIGATURE LAM WITH MEEM WITH JEEM INITIAL FORM */
}},
};
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */
+#endif /* HB_OT_SHAPER_ARABIC_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-win1256.hh
index 429974d05b..b8d481c813 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-win1256.hh
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#ifndef HB_OT_SHAPER_ARABIC_WIN1256_HH
/*
@@ -342,8 +342,8 @@ OT_TABLE_END
#include "hb.hh" /* Make check-includes.sh happy. */
#endif
#ifdef OT_MEASURE
-#include "hb-ot-shape-complex-arabic-win1256.hh"
+#include "hb-ot-shaper-arabic-win1256.hh"
#endif
-#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
+#define HB_OT_SHAPER_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPER_ARABIC_WIN1256_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
index 224f8b842e..e869d78509 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
@@ -28,14 +28,14 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-arabic.hh"
+#include "hb-ot-shaper-arabic.hh"
#include "hb-ot-shape.hh"
/* buffer var allocations */
-#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */
+#define arabic_shaping_action() ot_shaper_var_u8_auxiliary() /* arabic shaping action */
-#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
+#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_SHAPER0
/* See:
* https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
@@ -81,7 +81,7 @@ enum hb_arabic_joining_type_t {
JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
};
-#include "hb-ot-shape-complex-arabic-table.hh"
+#include "hb-ot-shaper-arabic-table.hh"
static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
{
@@ -172,6 +172,14 @@ record_stch (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer);
static void
+deallocate_buffer_var (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+}
+
+static void
collect_features_arabic (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
@@ -213,6 +221,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE);
map->add_gsub_pause (nullptr);
}
+ map->add_gsub_pause (deallocate_buffer_var);
/* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script
* however, it says a ZWJ should also mean "don't ligate". So we run
@@ -240,7 +249,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->enable_feature (HB_TAG('m','s','e','t'));
}
-#include "hb-ot-shape-complex-arabic-fallback.hh"
+#include "hb-ot-shaper-arabic-fallback.hh"
struct arabic_shape_plan_t
{
@@ -405,7 +414,7 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
-#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
+#ifdef HB_NO_OT_SHAPER_ARABIC_FALLBACK
return;
#endif
@@ -619,8 +628,6 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
apply_stch (plan, buffer, font);
-
- HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
/* https://www.unicode.org/reports/tr53/ */
@@ -689,7 +696,7 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Shift it! */
DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d", cc, i, j);
- hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS];
+ hb_glyph_info_t temp[HB_OT_SHAPE_MAX_COMBINING_MARKS];
assert (j - i <= ARRAY_LENGTH (temp));
buffer->merge_clusters (start, j);
memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t));
@@ -720,7 +727,7 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+const hb_ot_shaper_t _hb_ot_shaper_arabic =
{
collect_features_arabic,
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.hh
index 5bf6ff6338..a025b1a399 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.hh
@@ -26,12 +26,12 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_HH
+#ifndef HB_OT_SHAPER_ARABIC_HH
+#define HB_OT_SHAPER_ARABIC_HH
#include "hb.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
struct arabic_shape_plan_t;
@@ -47,4 +47,4 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_buffer_t *buffer,
hb_script_t script);
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_HH */
+#endif /* HB_OT_SHAPER_ARABIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-default.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc
index a755aea098..25716aa81f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-default.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc
@@ -28,10 +28,10 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+const hb_ot_shaper_t _hb_ot_shaper_default =
{
nullptr, /* collect_features */
nullptr, /* override_features */
@@ -51,7 +51,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
/* Same as default but no mark advance zeroing / fallback positioning.
* Dumbest shaper ever, basically. */
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber =
+const hb_ot_shaper_t _hb_ot_shaper_dumber =
{
nullptr, /* collect_features */
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc
index 3bc9e9b961..aa507c75ca 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc
@@ -28,7 +28,7 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
/* Hangul shaper */
@@ -119,7 +119,7 @@ data_destroy_hangul (void *data)
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */
-#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */
+#define hangul_shaping_feature() ot_shaper_var_u8_auxiliary() /* hangul jamo shaping feature */
static bool
is_zero_width_char (hb_font_t *font,
@@ -414,7 +414,7 @@ setup_masks_hangul (const hb_ot_shape_plan_t *plan,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
+const hb_ot_shaper_t _hb_ot_shaper_hangul =
{
collect_features_hangul,
override_features_hangul,
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hebrew.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc
index 334d3ded82..f3b6cde179 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc
@@ -28,7 +28,7 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
static bool
@@ -74,7 +74,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
bool found = (bool) c->unicode->compose (a, b, ab);
-#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+#ifdef HB_NO_OT_SHAPER_HEBREW_FALLBACK
return found;
#endif
@@ -163,7 +163,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
+const hb_ot_shaper_t _hb_ot_shaper_hebrew =
{
nullptr, /* collect_features */
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
new file mode 100644
index 0000000000..d52b13f616
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
@@ -0,0 +1,589 @@
+
+#line 1 "hb-ot-shaper-indic-machine.rl"
+/*
+ * Copyright © 2011,2012 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_INDIC_MACHINE_HH
+#define HB_OT_SHAPER_INDIC_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define indic_category() ot_shaper_var_u8_category() /* indic_category_t */
+#define indic_position() ot_shaper_var_u8_auxiliary() /* indic_position_t */
+
+using indic_category_t = unsigned;
+using indic_position_t = ot_position_t;
+
+#define I_Cat(Cat) indic_syllable_machine_ex_##Cat
+
+enum indic_syllable_type_t {
+ indic_consonant_syllable,
+ indic_vowel_syllable,
+ indic_standalone_cluster,
+ indic_symbol_cluster,
+ indic_broken_cluster,
+ indic_non_indic_cluster,
+};
+
+
+#line 57 "hb-ot-shaper-indic-machine.hh"
+#define indic_syllable_machine_ex_A 9u
+#define indic_syllable_machine_ex_C 1u
+#define indic_syllable_machine_ex_CM 16u
+#define indic_syllable_machine_ex_CS 18u
+#define indic_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define indic_syllable_machine_ex_H 4u
+#define indic_syllable_machine_ex_M 7u
+#define indic_syllable_machine_ex_N 3u
+#define indic_syllable_machine_ex_PLACEHOLDER 10u
+#define indic_syllable_machine_ex_RS 12u
+#define indic_syllable_machine_ex_Ra 15u
+#define indic_syllable_machine_ex_Repha 14u
+#define indic_syllable_machine_ex_SM 8u
+#define indic_syllable_machine_ex_Symbol 17u
+#define indic_syllable_machine_ex_V 2u
+#define indic_syllable_machine_ex_VD 9u
+#define indic_syllable_machine_ex_X 0u
+#define indic_syllable_machine_ex_ZWJ 6u
+#define indic_syllable_machine_ex_ZWNJ 5u
+
+
+#line 79 "hb-ot-shaper-indic-machine.hh"
+static const unsigned char _indic_syllable_machine_trans_keys[] = {
+ 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u,
+ 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u,
+ 5u, 8u, 4u, 8u, 4u, 8u, 4u, 12u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u,
+ 4u, 8u, 5u, 8u, 8u, 8u, 1u, 18u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u,
+ 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 1u, 15u, 3u, 9u,
+ 4u, 9u, 5u, 9u, 4u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u,
+ 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u,
+ 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u,
+ 4u, 9u, 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 8u,
+ 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u,
+ 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u,
+ 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 12u, 4u, 8u, 3u, 16u,
+ 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u,
+ 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 12u, 5u, 9u,
+ 9u, 9u, 5u, 9u, 1u, 15u, 3u, 9u, 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u,
+ 1u, 15u, 0
+};
+
+static const char _indic_syllable_machine_key_spans[] = {
+ 1, 5, 3, 4, 5, 9, 5, 1,
+ 3, 4, 5, 9, 9, 9, 1, 3,
+ 4, 5, 5, 9, 1, 3, 4, 5,
+ 5, 4, 1, 18, 14, 14, 13, 15,
+ 5, 5, 1, 5, 15, 15, 15, 7,
+ 6, 5, 6, 5, 7, 5, 14, 14,
+ 14, 14, 13, 15, 14, 14, 13, 15,
+ 5, 1, 5, 15, 15, 7, 6, 5,
+ 6, 5, 5, 7, 5, 14, 14, 5,
+ 14, 14, 13, 15, 14, 15, 5, 1,
+ 5, 15, 15, 7, 6, 5, 14, 6,
+ 5, 5, 7, 5, 14, 9, 5, 14,
+ 14, 13, 15, 14, 15, 5, 1, 5,
+ 15, 15, 7, 6, 5, 14, 6, 5,
+ 5, 7, 5, 16, 14, 16, 9, 5,
+ 1, 5, 15, 7, 5, 5, 1, 5,
+ 15
+};
+
+static const short _indic_syllable_machine_index_offsets[] = {
+ 0, 2, 8, 12, 17, 23, 33, 39,
+ 41, 45, 50, 56, 66, 76, 86, 88,
+ 92, 97, 103, 109, 119, 121, 125, 130,
+ 136, 142, 147, 149, 168, 183, 198, 212,
+ 228, 234, 240, 242, 248, 264, 280, 296,
+ 304, 311, 317, 324, 330, 338, 344, 359,
+ 374, 389, 404, 418, 434, 449, 464, 478,
+ 494, 500, 502, 508, 524, 540, 548, 555,
+ 561, 568, 574, 580, 588, 594, 609, 624,
+ 630, 645, 660, 674, 690, 705, 721, 727,
+ 729, 735, 751, 767, 775, 782, 788, 803,
+ 810, 816, 822, 830, 836, 851, 861, 867,
+ 882, 897, 911, 927, 942, 958, 964, 966,
+ 972, 988, 1004, 1012, 1019, 1025, 1040, 1047,
+ 1053, 1059, 1067, 1073, 1090, 1105, 1122, 1132,
+ 1138, 1140, 1146, 1162, 1170, 1176, 1182, 1184,
+ 1190
+};
+
+static const unsigned char _indic_syllable_machine_indicies[] = {
+ 1, 0, 2, 3, 3, 4, 1, 0,
+ 3, 3, 4, 0, 3, 3, 4, 1,
+ 0, 5, 3, 3, 4, 1, 0, 2,
+ 3, 3, 4, 1, 0, 0, 0, 6,
+ 0, 8, 9, 9, 10, 11, 7, 11,
+ 7, 9, 9, 10, 7, 9, 9, 10,
+ 11, 7, 12, 9, 9, 10, 11, 7,
+ 8, 9, 9, 10, 11, 7, 7, 7,
+ 13, 7, 8, 9, 9, 10, 11, 7,
+ 7, 7, 14, 7, 16, 17, 17, 18,
+ 19, 15, 15, 15, 20, 15, 19, 15,
+ 17, 17, 18, 21, 17, 17, 18, 19,
+ 15, 16, 17, 17, 18, 19, 15, 22,
+ 17, 17, 18, 19, 15, 24, 25, 25,
+ 26, 27, 23, 23, 23, 28, 23, 27,
+ 23, 25, 25, 26, 23, 25, 25, 26,
+ 27, 23, 24, 25, 25, 26, 27, 23,
+ 29, 25, 25, 26, 27, 23, 17, 17,
+ 18, 1, 0, 31, 30, 33, 34, 35,
+ 36, 37, 38, 18, 19, 39, 40, 40,
+ 20, 32, 41, 42, 43, 44, 45, 32,
+ 47, 48, 49, 50, 4, 1, 51, 46,
+ 46, 6, 46, 46, 46, 52, 46, 53,
+ 48, 54, 54, 4, 1, 51, 46, 46,
+ 46, 46, 46, 46, 52, 46, 48, 54,
+ 54, 4, 1, 51, 46, 46, 46, 46,
+ 46, 46, 52, 46, 33, 46, 46, 46,
+ 55, 56, 46, 1, 51, 46, 46, 46,
+ 46, 46, 33, 46, 57, 57, 46, 1,
+ 51, 46, 51, 46, 46, 58, 51, 46,
+ 51, 46, 51, 46, 46, 46, 51, 46,
+ 33, 46, 59, 46, 57, 57, 46, 1,
+ 51, 46, 46, 46, 46, 46, 33, 46,
+ 33, 46, 46, 46, 57, 57, 46, 1,
+ 51, 46, 46, 46, 46, 46, 33, 46,
+ 33, 46, 46, 46, 57, 56, 46, 1,
+ 51, 46, 46, 46, 46, 46, 33, 46,
+ 60, 61, 62, 62, 4, 1, 51, 46,
+ 61, 62, 62, 4, 1, 51, 46, 62,
+ 62, 4, 1, 51, 46, 63, 64, 64,
+ 4, 1, 51, 46, 55, 65, 46, 1,
+ 51, 46, 55, 46, 57, 57, 46, 1,
+ 51, 46, 57, 65, 46, 1, 51, 46,
+ 47, 48, 54, 54, 4, 1, 51, 46,
+ 46, 46, 46, 46, 46, 52, 46, 47,
+ 48, 49, 54, 4, 1, 51, 46, 46,
+ 6, 46, 46, 46, 52, 46, 67, 68,
+ 69, 70, 10, 11, 71, 66, 66, 14,
+ 66, 66, 66, 72, 66, 73, 68, 74,
+ 70, 10, 11, 71, 66, 66, 66, 66,
+ 66, 66, 72, 66, 68, 74, 70, 10,
+ 11, 71, 66, 66, 66, 66, 66, 66,
+ 72, 66, 75, 66, 66, 66, 76, 77,
+ 66, 11, 71, 66, 66, 66, 66, 66,
+ 75, 66, 78, 68, 79, 80, 10, 11,
+ 71, 66, 66, 13, 66, 66, 66, 72,
+ 66, 81, 68, 74, 74, 10, 11, 71,
+ 66, 66, 66, 66, 66, 66, 72, 66,
+ 68, 74, 74, 10, 11, 71, 66, 66,
+ 66, 66, 66, 66, 72, 66, 75, 66,
+ 66, 66, 82, 77, 66, 11, 71, 66,
+ 66, 66, 66, 66, 75, 66, 71, 66,
+ 66, 83, 71, 66, 71, 66, 71, 66,
+ 66, 66, 71, 66, 75, 66, 84, 66,
+ 82, 82, 66, 11, 71, 66, 66, 66,
+ 66, 66, 75, 66, 75, 66, 66, 66,
+ 82, 82, 66, 11, 71, 66, 66, 66,
+ 66, 66, 75, 66, 85, 86, 87, 87,
+ 10, 11, 71, 66, 86, 87, 87, 10,
+ 11, 71, 66, 87, 87, 10, 11, 71,
+ 66, 88, 89, 89, 10, 11, 71, 66,
+ 76, 90, 66, 11, 71, 66, 82, 82,
+ 66, 11, 71, 66, 76, 66, 82, 82,
+ 66, 11, 71, 66, 82, 90, 66, 11,
+ 71, 66, 78, 68, 74, 74, 10, 11,
+ 71, 66, 66, 66, 66, 66, 66, 72,
+ 66, 78, 68, 79, 74, 10, 11, 71,
+ 66, 66, 13, 66, 66, 66, 72, 66,
+ 8, 9, 9, 10, 11, 66, 67, 68,
+ 74, 70, 10, 11, 71, 66, 66, 66,
+ 66, 66, 66, 72, 66, 92, 36, 93,
+ 93, 18, 19, 39, 91, 91, 91, 91,
+ 91, 91, 43, 91, 36, 93, 93, 18,
+ 19, 39, 91, 91, 91, 91, 91, 91,
+ 43, 91, 94, 91, 91, 91, 95, 96,
+ 91, 19, 39, 91, 91, 91, 91, 91,
+ 94, 91, 35, 36, 97, 98, 18, 19,
+ 39, 91, 91, 20, 91, 91, 91, 43,
+ 91, 94, 91, 91, 91, 99, 96, 91,
+ 19, 39, 91, 91, 91, 91, 91, 94,
+ 91, 39, 91, 91, 100, 39, 91, 39,
+ 91, 39, 91, 91, 91, 39, 91, 94,
+ 91, 101, 91, 99, 99, 91, 19, 39,
+ 91, 91, 91, 91, 91, 94, 91, 94,
+ 91, 91, 91, 99, 99, 91, 19, 39,
+ 91, 91, 91, 91, 91, 94, 91, 102,
+ 103, 104, 104, 18, 19, 39, 91, 103,
+ 104, 104, 18, 19, 39, 91, 104, 104,
+ 18, 19, 39, 91, 35, 36, 93, 93,
+ 18, 19, 39, 91, 91, 91, 91, 91,
+ 91, 43, 91, 105, 106, 106, 18, 19,
+ 39, 91, 95, 107, 91, 19, 39, 91,
+ 99, 99, 91, 19, 39, 91, 95, 91,
+ 99, 99, 91, 19, 39, 91, 99, 107,
+ 91, 19, 39, 91, 35, 36, 97, 93,
+ 18, 19, 39, 91, 91, 20, 91, 91,
+ 91, 43, 91, 16, 17, 17, 18, 19,
+ 108, 108, 108, 20, 108, 16, 17, 17,
+ 18, 19, 108, 110, 111, 112, 113, 26,
+ 27, 114, 109, 109, 28, 109, 109, 109,
+ 115, 109, 116, 111, 113, 113, 26, 27,
+ 114, 109, 109, 109, 109, 109, 109, 115,
+ 109, 111, 113, 113, 26, 27, 114, 109,
+ 109, 109, 109, 109, 109, 115, 109, 117,
+ 109, 109, 109, 118, 119, 109, 27, 114,
+ 109, 109, 109, 109, 109, 117, 109, 110,
+ 111, 112, 40, 26, 27, 114, 109, 109,
+ 28, 109, 109, 109, 115, 109, 117, 109,
+ 109, 109, 120, 119, 109, 27, 114, 109,
+ 109, 109, 109, 109, 117, 109, 114, 109,
+ 109, 121, 114, 109, 114, 109, 114, 109,
+ 109, 109, 114, 109, 117, 109, 122, 109,
+ 120, 120, 109, 27, 114, 109, 109, 109,
+ 109, 109, 117, 109, 117, 109, 109, 109,
+ 120, 120, 109, 27, 114, 109, 109, 109,
+ 109, 109, 117, 109, 123, 124, 125, 125,
+ 26, 27, 114, 109, 124, 125, 125, 26,
+ 27, 114, 109, 125, 125, 26, 27, 114,
+ 109, 110, 111, 113, 113, 26, 27, 114,
+ 109, 109, 109, 109, 109, 109, 115, 109,
+ 126, 127, 127, 26, 27, 114, 109, 118,
+ 128, 109, 27, 114, 109, 120, 120, 109,
+ 27, 114, 109, 118, 109, 120, 120, 109,
+ 27, 114, 109, 120, 128, 109, 27, 114,
+ 109, 33, 34, 35, 36, 97, 93, 18,
+ 19, 39, 40, 40, 20, 91, 91, 33,
+ 43, 91, 47, 129, 49, 50, 4, 1,
+ 51, 46, 46, 6, 46, 46, 46, 52,
+ 46, 33, 34, 35, 36, 130, 131, 18,
+ 132, 133, 46, 40, 20, 46, 46, 33,
+ 43, 46, 16, 134, 134, 18, 132, 51,
+ 46, 46, 20, 46, 133, 46, 46, 135,
+ 133, 46, 133, 46, 133, 46, 46, 46,
+ 133, 46, 33, 46, 59, 16, 134, 134,
+ 18, 132, 51, 46, 46, 46, 46, 46,
+ 33, 46, 137, 136, 138, 138, 136, 31,
+ 139, 136, 138, 138, 136, 31, 139, 136,
+ 139, 136, 136, 140, 139, 136, 139, 136,
+ 139, 136, 136, 136, 139, 136, 33, 108,
+ 108, 108, 108, 108, 108, 108, 108, 40,
+ 108, 108, 108, 108, 33, 108, 0
+};
+
+static const unsigned char _indic_syllable_machine_trans_targs[] = {
+ 27, 33, 38, 2, 39, 45, 46, 27,
+ 55, 8, 61, 56, 68, 69, 72, 27,
+ 77, 15, 83, 78, 86, 27, 91, 27,
+ 100, 21, 106, 101, 109, 114, 27, 125,
+ 27, 28, 48, 73, 75, 93, 94, 79,
+ 95, 115, 116, 87, 123, 128, 27, 29,
+ 31, 5, 47, 34, 42, 30, 1, 32,
+ 36, 0, 35, 37, 40, 41, 3, 43,
+ 4, 44, 27, 49, 51, 12, 71, 57,
+ 64, 50, 6, 52, 66, 59, 53, 11,
+ 70, 54, 7, 58, 60, 62, 63, 9,
+ 65, 10, 67, 27, 74, 17, 76, 89,
+ 81, 13, 92, 14, 80, 82, 84, 85,
+ 16, 88, 18, 90, 27, 27, 96, 98,
+ 19, 23, 102, 110, 97, 99, 112, 104,
+ 20, 103, 105, 107, 108, 22, 111, 24,
+ 113, 117, 118, 122, 119, 120, 25, 121,
+ 27, 124, 26, 126, 127
+};
+
+static const char _indic_syllable_machine_trans_actions[] = {
+ 1, 0, 2, 0, 2, 2, 2, 3,
+ 2, 0, 2, 0, 2, 2, 2, 4,
+ 2, 0, 5, 0, 5, 6, 2, 7,
+ 2, 0, 2, 0, 2, 2, 8, 0,
+ 11, 2, 2, 5, 0, 12, 12, 0,
+ 2, 5, 2, 5, 2, 0, 13, 2,
+ 0, 0, 2, 0, 2, 2, 0, 2,
+ 2, 0, 0, 2, 2, 2, 0, 0,
+ 0, 2, 14, 2, 0, 0, 2, 0,
+ 2, 2, 0, 2, 2, 2, 2, 0,
+ 2, 2, 0, 0, 2, 2, 2, 0,
+ 0, 0, 2, 15, 5, 0, 5, 2,
+ 2, 0, 5, 0, 0, 2, 5, 5,
+ 0, 0, 0, 2, 16, 17, 2, 0,
+ 0, 0, 0, 2, 2, 2, 2, 2,
+ 0, 0, 2, 2, 2, 0, 0, 0,
+ 2, 0, 18, 18, 0, 0, 0, 0,
+ 19, 2, 0, 0, 0
+};
+
+static const char _indic_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, 9, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
+static const char _indic_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, 10, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
+static const short _indic_syllable_machine_eof_trans[] = {
+ 1, 1, 1, 1, 1, 1, 8, 8,
+ 8, 8, 8, 8, 8, 16, 16, 22,
+ 16, 16, 16, 24, 24, 24, 24, 24,
+ 24, 1, 31, 0, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 109, 109, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 92, 47, 47, 47, 47,
+ 47, 47, 47, 137, 137, 137, 137, 137,
+ 109
+};
+
+static const int indic_syllable_machine_start = 27;
+static const int indic_syllable_machine_first_final = 27;
+static const int indic_syllable_machine_error = -1;
+
+static const int indic_syllable_machine_en_main = 27;
+
+
+#line 58 "hb-ot-shaper-indic-machine.rl"
+
+
+
+#line 117 "hb-ot-shaper-indic-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+inline void
+find_syllables_indic (hb_buffer_t *buffer)
+{
+ unsigned int p, pe, eof, ts, te, act;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+#line 426 "hb-ot-shaper-indic-machine.hh"
+ {
+ cs = indic_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 137 "hb-ot-shaper-indic-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 442 "hb-ot-shaper-indic-machine.hh"
+ {
+ int _slen;
+ int _trans;
+ const unsigned char *_keys;
+ const unsigned char *_inds;
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ switch ( _indic_syllable_machine_from_state_actions[cs] ) {
+ case 10:
+#line 1 "NONE"
+ {ts = p;}
+ break;
+#line 456 "hb-ot-shaper-indic-machine.hh"
+ }
+
+ _keys = _indic_syllable_machine_trans_keys + (cs<<1);
+ _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
+
+ _slen = _indic_syllable_machine_key_spans[cs];
+ _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
+ ( info[p].indic_category()) <= _keys[1] ?
+ ( info[p].indic_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+ cs = _indic_syllable_machine_trans_targs[_trans];
+
+ if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
+ goto _again;
+
+ switch ( _indic_syllable_machine_trans_actions[_trans] ) {
+ case 2:
+#line 1 "NONE"
+ {te = p+1;}
+ break;
+ case 11:
+#line 113 "hb-ot-shaper-indic-machine.rl"
+ {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
+ break;
+ case 13:
+#line 108 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
+ break;
+ case 14:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
+ break;
+ case 17:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
+ break;
+ case 19:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
+ break;
+ case 15:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 16:
+#line 113 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
+ break;
+ case 1:
+#line 108 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
+ break;
+ case 3:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
+ break;
+ case 7:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
+ break;
+ case 8:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
+ break;
+ case 4:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 6:
+#line 1 "NONE"
+ { switch( act ) {
+ case 1:
+ {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
+ break;
+ case 5:
+ {{p = ((te))-1;} found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }
+ break;
+ case 6:
+ {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
+ break;
+ }
+ }
+ break;
+ case 18:
+#line 1 "NONE"
+ {te = p+1;}
+#line 108 "hb-ot-shaper-indic-machine.rl"
+ {act = 1;}
+ break;
+ case 5:
+#line 1 "NONE"
+ {te = p+1;}
+#line 112 "hb-ot-shaper-indic-machine.rl"
+ {act = 5;}
+ break;
+ case 12:
+#line 1 "NONE"
+ {te = p+1;}
+#line 113 "hb-ot-shaper-indic-machine.rl"
+ {act = 6;}
+ break;
+#line 559 "hb-ot-shaper-indic-machine.hh"
+ }
+
+_again:
+ switch ( _indic_syllable_machine_to_state_actions[cs] ) {
+ case 9:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 568 "hb-ot-shaper-indic-machine.hh"
+ }
+
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = _indic_syllable_machine_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ }
+
+#line 145 "hb-ot-shaper-indic-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
new file mode 100644
index 0000000000..8994f3ca59
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
@@ -0,0 +1,560 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-14.0.0.txt
+ * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
+ * # IndicPositionalCategory-14.0.0.txt
+ * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
+ * # Blocks-14.0.0.txt
+ * # Date: 2021-01-22, 23:29:00 GMT [KW]
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#include "hb-ot-shaper-indic.hh"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#include "hb-ot-shaper-indic-machine.hh"
+#include "hb-ot-shaper-khmer-machine.hh"
+#include "hb-ot-shaper-myanmar-machine.hh"
+
+/* indic */
+#define OT_X I_Cat(X)
+#define OT_C I_Cat(C)
+#define OT_V I_Cat(V)
+#define OT_N I_Cat(N)
+#define OT_H I_Cat(H)
+#define OT_ZWNJ I_Cat(ZWNJ)
+#define OT_ZWJ I_Cat(ZWJ)
+#define OT_M I_Cat(M)
+#define OT_SM I_Cat(SM)
+#define OT_A I_Cat(A)
+#define OT_VD I_Cat(VD)
+#define OT_PLACEHOLDER I_Cat(PLACEHOLDER)
+#define OT_DOTTEDCIRCLE I_Cat(DOTTEDCIRCLE)
+#define OT_RS I_Cat(RS)
+#define OT_Repha I_Cat(Repha)
+#define OT_Ra I_Cat(Ra)
+#define OT_CM I_Cat(CM)
+#define OT_Symbol I_Cat(Symbol)
+#define OT_CS I_Cat(CS)
+/* khmer */
+#define OT_VAbv K_Cat(VAbv)
+#define OT_VBlw K_Cat(VBlw)
+#define OT_VPre K_Cat(VPre)
+#define OT_VPst K_Cat(VPst)
+#define OT_Robatic K_Cat(Robatic)
+#define OT_Xgroup K_Cat(Xgroup)
+#define OT_Ygroup K_Cat(Ygroup)
+/* myanmar */
+static_assert (OT_VAbv == M_Cat(VAbv), "");
+static_assert (OT_VBlw == M_Cat(VBlw), "");
+static_assert (OT_VPre == M_Cat(VPre), "");
+static_assert (OT_VPst == M_Cat(VPst), "");
+#define OT_IV M_Cat(IV)
+#define OT_As M_Cat(As)
+#define OT_DB M_Cat(DB)
+#define OT_GB M_Cat(GB)
+#define OT_MH M_Cat(MH)
+#define OT_MR M_Cat(MR)
+#define OT_MW M_Cat(MW)
+#define OT_MY M_Cat(MY)
+#define OT_PT M_Cat(PT)
+#define OT_VS M_Cat(VS)
+#define OT_ML M_Cat(ML)
+
+
+#define _OT_A OT_A /* 53 chars; A */
+#define _OT_As OT_As /* 1 chars; As */
+#define _OT_C OT_C /* 478 chars; C */
+#define _OT_CM OT_CM /* 1 chars; CM */
+#define _OT_CS OT_CS /* 2 chars; CS */
+#define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */
+#define _OT_H OT_H /* 11 chars; H */
+#define _OT_M OT_M /* 143 chars; M */
+#define _OT_MH OT_MH /* 1 chars; MH */
+#define _OT_ML OT_ML /* 1 chars; ML */
+#define _OT_MR OT_MR /* 1 chars; MR */
+#define _OT_MW OT_MW /* 2 chars; MW */
+#define _OT_MY OT_MY /* 3 chars; MY */
+#define _OT_N OT_N /* 17 chars; N */
+#define _OT_GB OT_PLACEHOLDER /* 165 chars; PLACEHOLDER */
+#define _OT_PT OT_PT /* 8 chars; PT */
+#define _OT_R OT_Ra /* 14 chars; Ra */
+#define _OT_Rf OT_Repha /* 1 chars; Repha */
+#define _OT_Rt OT_Robatic /* 3 chars; Robatic */
+#define _OT_SM OT_SM /* 55 chars; SM */
+#define _OT_S OT_Symbol /* 22 chars; Symbol */
+#define _OT_V OT_V /* 172 chars; V */
+#define _OT_VA OT_VAbv /* 18 chars; VAbv */
+#define _OT_VB OT_VBlw /* 7 chars; VBlw */
+#define _OT_VL OT_VPre /* 5 chars; VPre */
+#define _OT_VR OT_VPst /* 13 chars; VPst */
+#define _OT_VS OT_VS /* 16 chars; VS */
+#define _OT_X OT_X /* 2 chars; X */
+#define _OT_Xg OT_Xgroup /* 7 chars; Xgroup */
+#define _OT_Yg OT_Ygroup /* 4 chars; Ygroup */
+#define _OT_ZWJ OT_ZWJ /* 1 chars; ZWJ */
+#define _OT_ZWNJ OT_ZWNJ /* 1 chars; ZWNJ */
+
+#define _POS_T POS_ABOVE_C /* 22 chars; ABOVE_C */
+#define _POS_A POS_AFTER_MAIN /* 3 chars; AFTER_MAIN */
+#define _POS_AP POS_AFTER_POST /* 50 chars; AFTER_POST */
+#define _POS_AS POS_AFTER_SUB /* 51 chars; AFTER_SUB */
+#define _POS_C POS_BASE_C /* 833 chars; BASE_C */
+#define _POS_BS POS_BEFORE_SUB /* 25 chars; BEFORE_SUB */
+#define _POS_B POS_BELOW_C /* 13 chars; BELOW_C */
+#define _POS_X POS_END /* 71 chars; END */
+#define _POS_R POS_POST_C /* 13 chars; POST_C */
+#define _POS_L POS_PRE_C /* 5 chars; PRE_C */
+#define _POS_LM POS_PRE_M /* 14 chars; PRE_M */
+#define _POS_SM POS_SMVD /* 129 chars; SMVD */
+
+#pragma GCC diagnostic pop
+
+#define INDIC_COMBINE_CATEGORIES(S,M) ((S) | ((M) << 8))
+
+#define _(S,M) INDIC_COMBINE_CATEGORIES (_OT_##S, _POS_##M)
+
+
+static const uint16_t indic_table[] = {
+
+
+#define indic_offset_0x0028u 0
+
+
+ /* Basic Latin */
+
+ /* 0028 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X),
+ /* 0030 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0038 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x00b0u 24
+
+
+ /* Latin-1 Supplement */
+
+ /* 00B0 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 00B8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 00C0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 00C8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 00D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C),
+
+#define indic_offset_0x0900u 64
+
+
+ /* Devanagari */
+
+ /* 0900 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 0908 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 0910 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0918 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0920 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0928 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0930 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0938 */ _(C,C), _(C,C), _(M,AS), _(M,AS), _(N,X), _(S,SM), _(M,AS), _(M,LM),
+ /* 0940 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS),
+ /* 0948 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(H,B), _(M,LM), _(M,AS),
+ /* 0950 */ _(X,X), _(A,SM), _(A,SM),_(SM,SM),_(SM,SM), _(M,AS), _(M,AS), _(M,AS),
+ /* 0958 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0960 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0968 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0970 */ _(X,X), _(X,X), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 0978 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+
+ /* Bengali */
+
+ /* 0980 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0988 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C),
+ /* 0990 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0998 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 09A0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 09A8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 09B0 */ _(R,C), _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C),
+ /* 09B8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM),
+ /* 09C0 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM),
+ /* 09C8 */ _(M,LM), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(C,C), _(X,X),
+ /* 09D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP),
+ /* 09D8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C),
+ /* 09E0 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 09E8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 09F0 */ _(R,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 09F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X),_(SM,SM), _(X,X),
+
+ /* Gurmukhi */
+
+ /* 0A00 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0A08 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C),
+ /* 0A10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0A18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0A20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0A28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0A30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(X,X),
+ /* 0A38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(X,X), _(M,AP), _(M,LM),
+ /* 0A40 */ _(M,AP), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP),
+ /* 0A48 */ _(M,AP), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X),
+ /* 0A50 */ _(X,X), _(M,B), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0A58 */ _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X),
+ /* 0A60 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0A68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0A70 */_(SM,SM),_(SM,SM), _(C,C), _(C,C), _(X,X), _(CM,C), _(X,X), _(X,X),
+ /* 0A78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+ /* Gujarati */
+
+ /* 0A80 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0A88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C),
+ /* 0A90 */ _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0A98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0AA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0AA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0AB0 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C),
+ /* 0AB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM),
+ /* 0AC0 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AS), _(X,X), _(M,AS),
+ /* 0AC8 */ _(M,AS), _(M,AP), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X),
+ /* 0AD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0AD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0AE0 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0AE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0AF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0AF8 */ _(X,X), _(C,C), _(A,SM), _(N,X), _(A,SM), _(N,X), _(N,X), _(N,X),
+
+ /* Oriya */
+
+ /* 0B00 */ _(X,X),_(SM,BS),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0B08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C),
+ /* 0B10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0B18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0B20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0B28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0B30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C),
+ /* 0B38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,A),
+ /* 0B40 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM),
+ /* 0B48 */ _(M,A), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X),
+ /* 0B50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(N,X), _(M,A), _(M,AP),
+ /* 0B58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C),
+ /* 0B60 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0B68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0B70 */ _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0B78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+ /* Tamil */
+
+ /* 0B80 */ _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0B88 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(V,C), _(V,C),
+ /* 0B90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(X,X), _(X,X),
+ /* 0B98 */ _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X), _(C,C), _(C,C),
+ /* 0BA0 */ _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X),
+ /* 0BA8 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C),
+ /* 0BB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0BB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), _(M,AP),
+ /* 0BC0 */ _(M,AS), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(M,LM), _(M,LM),
+ /* 0BC8 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(X,X), _(X,X),
+ /* 0BD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP),
+ /* 0BD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0BE0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0BE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0BF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0BF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+ /* Telugu */
+
+ /* 0C00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C),
+ /* 0C08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C),
+ /* 0C10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0C18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0C20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0C28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0C30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0C38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS),
+ /* 0C40 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,BS),
+ /* 0C48 */ _(M,BS), _(X,X), _(M,BS), _(M,BS), _(M,BS), _(H,T), _(X,X), _(X,X),
+ /* 0C50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,BS), _(M,BS), _(X,X),
+ /* 0C58 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(C,C), _(X,X), _(X,X),
+ /* 0C60 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0C68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0C70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0C78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+ /* Kannada */
+
+ /* 0C80 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C),
+ /* 0C88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C),
+ /* 0C90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0C98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0CA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0CA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0CB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C),
+ /* 0CB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS),
+ /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,AS),
+ /* 0CC8 */ _(M,AS), _(X,X), _(M,AS), _(M,AS), _(M,BS), _(H,T), _(X,X), _(X,X),
+ /* 0CD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AS), _(M,AS), _(X,X),
+ /* 0CD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X),
+ /* 0CE0 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0CF0 */ _(X,X), _(CS,C), _(CS,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0CF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+ /* Malayalam */
+
+ /* 0D00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(GB,C), _(V,C), _(V,C), _(V,C),
+ /* 0D08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C),
+ /* 0D10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C),
+ /* 0D18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0D20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0D28 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0D30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 0D38 */ _(C,C), _(C,C), _(C,C), _(M,AS), _(M,AS), _(S,SM), _(M,AP), _(M,AP),
+ /* 0D40 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(X,X), _(M,LM), _(M,LM),
+ /* 0D48 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(Rf,X), _(X,X),
+ /* 0D50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(M,AP),
+ /* 0D58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C),
+ /* 0D60 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C),
+ /* 0D68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 0D70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 0D78 */ _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+
+#define indic_offset_0x1000u 1216
+
+
+ /* Myanmar */
+
+ /* 1000 */ _(C,C), _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C),
+ /* 1008 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1010 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1018 */ _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1020 */ _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 1028 */ _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R), _(VA,T), _(VA,T), _(VB,B),
+ /* 1030 */ _(VB,B), _(VL,L), _(A,SM), _(VA,T), _(VA,T), _(VA,T), _(A,SM), _(N,X),
+ /* 1038 */_(SM,SM), _(H,X), _(As,X), _(MY,X), _(MR,X), _(MW,X), _(MH,X), _(C,C),
+ /* 1040 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 1048 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), _(C,C), _(X,X),
+ /* 1050 */ _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R),
+ /* 1058 */ _(VB,B), _(VB,B), _(R,C), _(C,C), _(C,C), _(C,C), _(MY,X), _(MY,X),
+ /* 1060 */ _(ML,X), _(C,C), _(VR,R), _(PT,X), _(PT,X), _(C,C), _(C,C), _(VR,R),
+ /* 1068 */ _(VR,R), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(C,C), _(C,C),
+ /* 1070 */ _(C,C), _(VA,T), _(VA,T), _(VA,T), _(VA,T), _(C,C), _(C,C), _(C,C),
+ /* 1078 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1080 */ _(C,C), _(C,C), _(MW,X), _(VR,R), _(VL,L), _(VA,T), _(VA,T),_(SM,SM),
+ /* 1088 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(C,C),_(SM,SM),
+ /* 1090 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 1098 */ _(GB,C), _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(VA,T), _(X,X), _(X,X),
+
+#define indic_offset_0x1780u 1376
+
+
+ /* Khmer */
+
+ /* 1780 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1788 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1790 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 1798 */ _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* 17A0 */ _(C,C), _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 17A8 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C),
+ /* 17B0 */ _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(VR,R), _(VA,T),
+ /* 17B8 */ _(VA,T), _(VA,T), _(VA,T), _(VB,B), _(VB,B), _(VB,B), _(VA,T), _(VR,R),
+ /* 17C0 */ _(VR,R), _(VL,L), _(VL,L), _(VL,L), _(VR,R), _(VR,R), _(Xg,X), _(Yg,X),
+ /* 17C8 */ _(Yg,X), _(Rt,X), _(Rt,X), _(Xg,X), _(Rt,X), _(Xg,X), _(Xg,X), _(Xg,X),
+ /* 17D0 */ _(Xg,X), _(Xg,X), _(H,X), _(Yg,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 17D8 */ _(X,X), _(GB,C), _(X,X), _(X,X), _(S,SM), _(Yg,X), _(X,X), _(X,X),
+ /* 17E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* 17E8 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x1cd0u 1488
+
+
+ /* Vedic Extensions */
+
+ /* 1CD0 */ _(A,SM), _(A,SM), _(A,SM), _(X,X), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+ /* 1CD8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+ /* 1CE0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+ /* 1CE8 */ _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(A,SM), _(S,SM), _(S,SM),
+ /* 1CF0 */ _(S,SM), _(S,SM), _(C,C), _(C,C), _(A,SM), _(C,C), _(C,C), _(A,SM),
+ /* 1CF8 */ _(A,SM), _(A,SM), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x2008u 1536
+
+
+ /* General Punctuation */
+
+ /* 2008 */ _(X,X), _(X,X), _(X,X), _(X,X),_(ZWNJ,X),_(ZWJ,X), _(X,X), _(X,X),
+ /* 2010 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X),
+ /* 2018 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 2020 */ _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x2070u 1568
+
+
+ /* Superscripts and Subscripts */
+
+ /* 2070 */ _(X,X), _(X,X), _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(X,X),
+ /* 2078 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 2080 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X),
+
+#define indic_offset_0x25f8u 1592
+
+
+ /* Geometric Shapes */
+
+ /* 25F8 */ _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X),
+
+#define indic_offset_0xa8e0u 1600
+
+
+ /* Devanagari Extended */
+
+ /* A8E0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+ /* A8E8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+ /* A8F0 */ _(A,SM), _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM),
+ /* A8F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), _(M,AS),
+
+#define indic_offset_0xa9e0u 1632
+
+
+ /* Myanmar Extended-B */
+
+ /* A9E0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(VA,T), _(X,X), _(C,C),
+ /* A9E8 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* A9F0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+ /* A9F8 */ _(GB,C), _(GB,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X),
+
+#define indic_offset_0xaa60u 1664
+
+
+ /* Myanmar Extended-A */
+
+ /* AA60 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* AA68 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C),
+ /* AA70 */ _(X,X), _(C,C), _(C,C), _(C,C), _(GB,C), _(GB,C), _(GB,C), _(X,X),
+ /* AA78 */ _(X,X), _(X,X), _(C,C), _(PT,X), _(N,X), _(N,X), _(C,C), _(C,C),
+
+#define indic_offset_0xfe00u 1696
+
+
+ /* Variation Selectors */
+
+ /* FE00 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X),
+ /* FE08 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X),
+
+#define indic_offset_0x11300u 1712
+
+
+ /* Grantha */
+
+ /* 11300 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11308 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11310 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11318 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11320 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11328 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11330 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
+ /* 11338 */ _(X,X), _(X,X), _(X,X), _(N,X), _(N,X), _(X,X), _(X,X), _(X,X),
+
+}; /* Table items: 1776; occupancy: 69% */
+
+uint16_t
+hb_indic_get_categories (hb_codepoint_t u)
+{
+ switch (u >> 12)
+ {
+ case 0x0u:
+ if (unlikely (u == 0x00A0u)) return _(GB,C);
+ if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0D7Fu)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+ break;
+
+ case 0x1u:
+ if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+ break;
+
+ case 0x2u:
+ if (unlikely (u == 0x25CCu)) return _(DC,C);
+ if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2027u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x25F8u, 0x25FFu)) return indic_table[u - 0x25F8u + indic_offset_0x25f8u];
+ break;
+
+ case 0xAu:
+ if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
+ if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
+ if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
+ break;
+
+ case 0xFu:
+ if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return indic_table[u - 0xFE00u + indic_offset_0xfe00u];
+ break;
+
+ case 0x11u:
+ if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x1133Fu)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
+ break;
+
+ default:
+ break;
+ }
+ return _(X,X);
+}
+
+#undef _
+#undef INDIC_COMBINE_CATEGORIES
+
+#undef _OT_A
+#undef _OT_As
+#undef _OT_C
+#undef _OT_CM
+#undef _OT_CS
+#undef _OT_DC
+#undef _OT_H
+#undef _OT_M
+#undef _OT_MH
+#undef _OT_ML
+#undef _OT_MR
+#undef _OT_MW
+#undef _OT_MY
+#undef _OT_N
+#undef _OT_GB
+#undef _OT_PT
+#undef _OT_R
+#undef _OT_Rf
+#undef _OT_Rt
+#undef _OT_SM
+#undef _OT_S
+#undef _OT_V
+#undef _OT_VA
+#undef _OT_VB
+#undef _OT_VL
+#undef _OT_VR
+#undef _OT_VS
+#undef _OT_X
+#undef _OT_Xg
+#undef _OT_Yg
+#undef _OT_ZWJ
+#undef _OT_ZWNJ
+
+#undef _POS_T
+#undef _POS_A
+#undef _POS_AP
+#undef _POS_AS
+#undef _POS_C
+#undef _POS_BS
+#undef _POS_B
+#undef _POS_X
+#undef _POS_R
+#undef _POS_L
+#undef _POS_LM
+#undef _POS_SM
+
+#endif
+
+/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
index c80f7df6a9..48a3c74463 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc
@@ -28,9 +28,9 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-indic.hh"
-#include "hb-ot-shape-complex-indic-machine.hh"
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-indic.hh"
+#include "hb-ot-shaper-indic-machine.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
#include "hb-ot-layout.hh"
@@ -39,6 +39,81 @@
*/
+static inline void
+set_indic_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+
+ info.indic_category() = (indic_category_t) (type & 0xFFu);
+ info.indic_position() = (indic_position_t) (type >> 8);
+}
+
+
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+ return !!(FLAG_UNSAFE (info.indic_category()) & flags);
+}
+
+/* Note:
+ *
+ * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
+ * cannot happen in a consonant syllable. The plus side however is, we can call the
+ * consonant syllable logic from the vowel syllable function and get it all right!
+ *
+ * Keep in sync with consonant_categories in the generator. */
+#define CONSONANT_FLAGS_INDIC (FLAG (I_Cat(C)) | FLAG (I_Cat(CS)) | FLAG (I_Cat(Ra)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(V)) | FLAG (I_Cat(PLACEHOLDER)) | FLAG (I_Cat(DOTTEDCIRCLE)))
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, CONSONANT_FLAGS_INDIC);
+}
+
+#define JOINER_FLAGS (FLAG (I_Cat(ZWJ)) | FLAG (I_Cat(ZWNJ)))
+
+static inline bool
+is_joiner (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, JOINER_FLAGS);
+}
+
+static inline bool
+is_halant (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, FLAG (I_Cat(H)));
+}
+
+struct hb_indic_would_substitute_feature_t
+{
+ void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+ {
+ zero_context = zero_context_;
+ map->get_stage_lookups (0/*GSUB*/,
+ map->get_feature_stage (0/*GSUB*/, feature_tag),
+ &lookups, &count);
+ }
+
+ bool would_substitute (const hb_codepoint_t *glyphs,
+ unsigned int glyphs_count,
+ hb_face_t *face) const
+ {
+ for (unsigned int i = 0; i < count; i++)
+ if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+ return true;
+ return false;
+ }
+
+ private:
+ const hb_ot_map_t::lookup_map_t *lookups;
+ unsigned int count;
+ bool zero_context;
+};
+
+
/*
* Indic configurations. Note that we do not want to keep every single script-specific
* behavior in these tables necessarily. This should mainly be used for per-script
@@ -47,10 +122,6 @@
* instead of adding a new flag in these structs.
*/
-enum base_position_t {
- BASE_POS_LAST_SINHALA,
- BASE_POS_LAST
-};
enum reph_position_t {
REPH_POS_AFTER_MAIN = POS_AFTER_MAIN,
REPH_POS_BEFORE_SUB = POS_BEFORE_SUB,
@@ -72,7 +143,6 @@ struct indic_config_t
hb_script_t script;
bool has_old_spec;
hb_codepoint_t virama;
- base_position_t base_pos;
reph_position_t reph_pos;
reph_mode_t reph_mode;
blwf_mode_t blwf_mode;
@@ -81,26 +151,19 @@ struct indic_config_t
static const indic_config_t indic_configs[] =
{
/* Default. Should be first. */
- {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
- {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
- {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
- {HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA,
- REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_INVALID, false, 0,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_DEVANAGARI,true, 0x094Du,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_BENGALI, true, 0x09CDu,REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_GUJARATI, true, 0x0ACDu,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_ORIYA, true, 0x0B4Du,REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_TAMIL, true, 0x0BCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_TELUGU, true, 0x0C4Du,REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
+ {HB_SCRIPT_KANNADA, true, 0x0CCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
+ {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
};
-
-/*
- * Indic shaper.
- */
-
static const hb_ot_map_feature_t
indic_features[] =
{
@@ -207,6 +270,7 @@ static void
override_features_indic (hb_ot_shape_planner_t *plan)
{
plan->map.disable_feature (HB_TAG('l','i','g','a'));
+ plan->map.add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
}
@@ -356,6 +420,7 @@ setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
+ HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
find_syllables_indic (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
@@ -367,7 +432,7 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
int a = pa->indic_position();
int b = pb->indic_position();
- return a < b ? -1 : a == b ? 0 : +1;
+ return (int) a - (int) b;
}
@@ -379,9 +444,6 @@ update_consonant_positions_indic (const hb_ot_shape_plan_t *plan,
{
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
- if (indic_plan->config->base_pos != BASE_POS_LAST)
- return;
-
hb_codepoint_t virama;
if (indic_plan->load_virama_glyph (font, &virama))
{
@@ -416,9 +478,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
*/
if (buffer->props.script == HB_SCRIPT_KANNADA &&
start + 3 <= end &&
- is_one_of (info[start ], FLAG (OT_Ra)) &&
- is_one_of (info[start+1], FLAG (OT_H)) &&
- is_one_of (info[start+2], FLAG (OT_ZWJ)))
+ is_one_of (info[start ], FLAG (I_Cat(Ra))) &&
+ is_one_of (info[start+1], FLAG (I_Cat(H))) &&
+ is_one_of (info[start+2], FLAG (I_Cat(ZWJ))))
{
buffer->merge_clusters (start+1, start+3);
hb_glyph_info_t tmp = info[start+1];
@@ -452,7 +514,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
start + 3 <= end &&
(
(indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
- (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
+ (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == I_Cat(ZWJ))
))
{
/* See if it matches the 'rphf' feature. */
@@ -470,7 +532,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
base = start;
has_reph = true;
}
- } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
+ } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == I_Cat(Repha))
{
limit += 1;
while (limit < end && is_joiner (info[limit]))
@@ -479,84 +541,51 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
has_reph = true;
}
- switch (indic_plan->config->base_pos)
{
- case BASE_POS_LAST:
- {
- /* -> starting from the end of the syllable, move backwards */
- unsigned int i = end;
- bool seen_below = false;
- do {
- i--;
- /* -> until a consonant is found */
- if (is_consonant (info[i]))
+ /* -> starting from the end of the syllable, move backwards */
+ unsigned int i = end;
+ bool seen_below = false;
+ do {
+ i--;
+ /* -> until a consonant is found */
+ if (is_consonant (info[i]))
+ {
+ /* -> that does not have a below-base or post-base form
+ * (post-base forms have to follow below-base forms), */
+ if (info[i].indic_position() != POS_BELOW_C &&
+ (info[i].indic_position() != POS_POST_C || seen_below))
{
- /* -> that does not have a below-base or post-base form
- * (post-base forms have to follow below-base forms), */
- if (info[i].indic_position() != POS_BELOW_C &&
- (info[i].indic_position() != POS_POST_C || seen_below))
- {
- base = i;
- break;
- }
- if (info[i].indic_position() == POS_BELOW_C)
- seen_below = true;
-
- /* -> or that is not a pre-base-reordering Ra,
- *
- * IMPLEMENTATION NOTES:
- *
- * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped
- * by the logic above already.
- */
-
- /* -> or arrive at the first consonant. The consonant stopped at will
- * be the base. */
base = i;
+ break;
}
- else
- {
- /* A ZWJ after a Halant stops the base search, and requests an explicit
- * half form.
- * A ZWJ before a Halant, requests a subjoined form instead, and hence
- * search continues. This is particularly important for Bengali
- * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
- if (start < i &&
- info[i].indic_category() == OT_ZWJ &&
- info[i - 1].indic_category() == OT_H)
- break;
- }
- } while (i > limit);
- }
- break;
-
- case BASE_POS_LAST_SINHALA:
- {
- /* Sinhala base positioning is slightly different from main Indic, in that:
- * 1. Its ZWJ behavior is different,
- * 2. We don't need to look into the font for consonant positions.
- */
-
- if (!has_reph)
- base = limit;
+ if (info[i].indic_position() == POS_BELOW_C)
+ seen_below = true;
- /* Find the last base consonant that is not blocked by ZWJ. If there is
- * a ZWJ right before a base consonant, that would request a subjoined form. */
- for (unsigned int i = limit; i < end; i++)
- if (is_consonant (info[i]))
- {
- if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
- break;
- else
- base = i;
- }
+ /* -> or that is not a pre-base-reordering Ra,
+ *
+ * IMPLEMENTATION NOTES:
+ *
+ * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped
+ * by the logic above already.
+ */
- /* Mark all subsequent consonants as below. */
- for (unsigned int i = base + 1; i < end; i++)
- if (is_consonant (info[i]))
- info[i].indic_position() = POS_BELOW_C;
- }
- break;
+ /* -> or arrive at the first consonant. The consonant stopped at will
+ * be the base. */
+ base = i;
+ }
+ else
+ {
+ /* A ZWJ after a Halant stops the base search, and requests an explicit
+ * half form.
+ * A ZWJ before a Halant, requests a subjoined form instead, and hence
+ * search continues. This is particularly important for Bengali
+ * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
+ if (start < i &&
+ info[i].indic_category() == I_Cat(ZWJ) &&
+ info[i - 1].indic_category() == I_Cat(H))
+ break;
+ }
+ } while (i > limit);
}
/* -> If the syllable starts with Ra + Halant (in a script that has Reph)
@@ -611,18 +640,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
if (base < end)
info[base].indic_position() = POS_BASE_C;
- /* Mark final consonants. A final consonant is one appearing after a matra.
- * Happens in Sinhala. */
- for (unsigned int i = base + 1; i < end; i++)
- if (info[i].indic_category() == OT_M) {
- for (unsigned int j = i + 1; j < end; j++)
- if (is_consonant (info[j])) {
- info[j].indic_position() = POS_FINAL_C;
- break;
- }
- break;
- }
-
/* Handle beginning Ra */
if (has_reph)
info[start].indic_position() = POS_RA_TO_BECOME_REPH;
@@ -659,14 +676,14 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
{
bool disallow_double_halants = buffer->props.script == HB_SCRIPT_KANNADA;
for (unsigned int i = base + 1; i < end; i++)
- if (info[i].indic_category() == OT_H)
+ if (info[i].indic_category() == I_Cat(H))
{
unsigned int j;
for (j = end - 1; j > i; j--)
if (is_consonant (info[j]) ||
- (disallow_double_halants && info[j].indic_category() == OT_H))
+ (disallow_double_halants && info[j].indic_category() == I_Cat(H)))
break;
- if (info[j].indic_category() != OT_H && j > i) {
+ if (info[j].indic_category() != I_Cat(H) && j > i) {
/* Move Halant to after last consonant. */
hb_glyph_info_t t = info[i];
memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
@@ -681,20 +698,16 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
indic_position_t last_pos = POS_START;
for (unsigned int i = start; i < end; i++)
{
- if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H))))
+ if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (I_Cat(N)) | FLAG (I_Cat(RS)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(H)))))
{
info[i].indic_position() = last_pos;
- if (unlikely (info[i].indic_category() == OT_H &&
+ if (unlikely (info[i].indic_category() == I_Cat(H) &&
info[i].indic_position() == POS_PRE_M))
{
/*
* Uniscribe doesn't move the Halant with Left Matra.
- * TEST: U+092B,U+093F,U+094DE
- * We follow. This is important for the Sinhala
- * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
- * where U+0DD9 is a left matra and U+0DCA is the virama.
- * We don't want to move the virama with the left matra.
- * TEST: U+0D9A,U+0DDA
+ * TEST: U+092B,U+093F,U+094D
+ * We follow.
*/
for (unsigned int j = i; j > start; j--)
if (info[j - 1].indic_position() != POS_PRE_M) {
@@ -718,7 +731,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
if (info[j].indic_position() < POS_SMVD)
info[j].indic_position() = info[i].indic_position();
last = i;
- } else if (info[i].indic_category() == OT_M)
+ } else if (info[i].indic_category() == I_Cat(M))
last = i;
}
@@ -849,10 +862,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
*/
for (unsigned int i = start; i + 1 < base; i++)
- if (info[i ].indic_category() == OT_Ra &&
- info[i+1].indic_category() == OT_H &&
+ if (info[i ].indic_category() == I_Cat(Ra) &&
+ info[i+1].indic_category() == I_Cat(H) &&
(i + 2 == base ||
- info[i+2].indic_category() != OT_ZWJ))
+ info[i+2].indic_category() != I_Cat(ZWJ)))
{
info[i ].mask |= indic_plan->mask_array[INDIC_BLWF];
info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF];
@@ -879,7 +892,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Apply ZWJ/ZWNJ effects */
for (unsigned int i = start + 1; i < end; i++)
if (is_joiner (info[i])) {
- bool non_joiner = info[i].indic_category() == OT_ZWNJ;
+ bool non_joiner = info[i].indic_category() == I_Cat(ZWNJ);
unsigned int j = i;
do {
@@ -912,7 +925,7 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
/* For dotted-circle, this is what Uniscribe does:
* If dotted-circle is the last glyph, it just does nothing.
* Ie. It doesn't form Reph. */
- if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
+ if (buffer->info[end - 1].indic_category() == I_Cat(DOTTEDCIRCLE))
return;
}
@@ -955,8 +968,8 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan,
update_consonant_positions_indic (plan, font, buffer);
hb_syllabic_insert_dotted_circles (font, buffer,
indic_broken_cluster,
- OT_DOTTEDCIRCLE,
- OT_Repha,
+ I_Cat(DOTTEDCIRCLE),
+ I_Cat(Repha),
POS_END);
foreach_syllable (buffer, start, end)
@@ -978,7 +991,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
* and possibly multiple substitutions happened prior to this
* phase, and that might have messed up our properties. Recover
* from a particular case of that where we're fairly sure that a
- * class of OT_H is desired but has been lost. */
+ * class of I_Cat(H) is desired but has been lost. */
/* We don't call load_virama_glyph(), since we know it's already
* loaded. */
hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed ();
@@ -990,7 +1003,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
_hb_glyph_info_multiplied (&info[i]))
{
/* This will make sure that this glyph passes is_halant() test. */
- info[i].indic_category() = OT_H;
+ info[i].indic_category() = I_Cat(H);
_hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
}
}
@@ -1056,11 +1069,11 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
break;
}
if (base == end && start < base &&
- is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+ is_one_of (info[base - 1], FLAG (I_Cat(ZWJ))))
base--;
if (base < end)
while (start < base &&
- is_one_of (info[base], (FLAG (OT_N) | FLAG (OT_H))))
+ is_one_of (info[base], (FLAG (I_Cat(N)) | FLAG (I_Cat(H)))))
base--;
@@ -1105,7 +1118,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
{
search:
while (new_pos > start &&
- !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H)))))
+ !(is_one_of (info[new_pos], (FLAG (I_Cat(M)) | FLAG (I_Cat(H))))))
new_pos--;
/* If we found no Halant we are done.
@@ -1122,7 +1135,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
if (new_pos + 1 < end)
{
/* -> If ZWJ follows this halant, matra is NOT repositioned after this halant. */
- if (info[new_pos + 1].indic_category() == OT_ZWJ)
+ if (info[new_pos + 1].indic_category() == I_Cat(ZWJ))
{
/* Keep searching. */
if (new_pos > start)
@@ -1195,7 +1208,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
*/
if (start + 1 < end &&
info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
- ((info[start].indic_category() == OT_Repha) ^
+ ((info[start].indic_category() == I_Cat(Repha)) ^
_hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
{
unsigned int new_reph_pos;
@@ -1305,7 +1318,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
unlikely (is_halant (info[new_reph_pos])))
{
for (unsigned int i = base + 1; i < new_reph_pos; i++)
- if (info[i].indic_category() == OT_M) {
+ if (info[i].indic_category() == I_Cat(M)) {
/* Ok, got it. */
new_reph_pos--;
}
@@ -1365,7 +1378,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
while (new_pos > start &&
- !(is_one_of (info[new_pos - 1], FLAG(OT_M) | FLAG (OT_H))))
+ !(is_one_of (info[new_pos - 1], FLAG(I_Cat(M)) | FLAG (I_Cat(H)))))
new_pos--;
}
@@ -1414,11 +1427,10 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
switch ((hb_tag_t) plan->props.script)
{
case HB_SCRIPT_TAMIL:
- case HB_SCRIPT_SINHALA:
break;
default:
- /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala.
+ /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil.
* This means, half forms are submerged into the main consonant's cluster.
* This is unnecessary, and makes cursor positioning harder, but that's what
* Uniscribe does. */
@@ -1453,7 +1465,9 @@ preprocess_text_indic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
- _hb_preprocess_text_vowel_constraints (plan, buffer, font);
+ const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+ if (!indic_plan->uniscribe_bug_compatible)
+ _hb_preprocess_text_vowel_constraints (plan, buffer, font);
}
static bool
@@ -1486,48 +1500,6 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
#endif
}
- if ((ab == 0x0DDAu || hb_in_range<hb_codepoint_t> (ab, 0x0DDCu, 0x0DDEu)))
- {
- /*
- * Sinhala split matras... Let the fun begin.
- *
- * These four characters have Unicode decompositions. However, Uniscribe
- * decomposes them "Khmer-style", that is, it uses the character itself to
- * get the second half. The first half of all four decompositions is always
- * U+0DD9.
- *
- * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
- * broken with Uniscribe. But we need to support them. As such, we only
- * do the Uniscribe-style decomposition if the character is transformed into
- * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to
- * Unicode decomposition.
- *
- * Note that we can't unconditionally use Unicode decomposition. That would
- * break some other fonts, that are designed to work with Uniscribe, and
- * don't have positioning features for the Unicode-style decomposition.
- *
- * Argh...
- *
- * The Uniscribe behavior is now documented in the newly published Sinhala
- * spec in 2012:
- *
- * https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping
- */
-
-
- const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
- hb_codepoint_t glyph;
- if (indic_plan->uniscribe_bug_compatible ||
- (c->font->get_nominal_glyph (ab, &glyph) &&
- indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
- {
- /* Ok, safe to use Uniscribe-style decomposition. */
- *a = 0x0DD9u;
- *b = ab;
- return true;
- }
- }
-
return (bool) c->unicode->decompose (ab, a, b);
}
@@ -1548,7 +1520,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+const hb_ot_shaper_t _hb_ot_shaper_indic =
{
collect_features_indic,
override_features_indic,
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh
new file mode 100644
index 0000000000..4f822c26e9
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2012 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_INDIC_HH
+#define HB_OT_SHAPER_INDIC_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-syllabic.hh"
+
+
+/* Visual positions in a syllable from left to right. */
+enum ot_position_t {
+ POS_START = 0,
+
+ POS_RA_TO_BECOME_REPH = 1,
+ POS_PRE_M = 2,
+ POS_PRE_C = 3,
+
+ POS_BASE_C = 4,
+ POS_AFTER_MAIN = 5,
+
+ POS_ABOVE_C = 6,
+
+ POS_BEFORE_SUB = 7,
+ POS_BELOW_C = 8,
+ POS_AFTER_SUB = 9,
+
+ POS_BEFORE_POST = 10,
+ POS_POST_C = 11,
+ POS_AFTER_POST = 12,
+
+ POS_SMVD = 13,
+
+ POS_END = 14
+};
+
+
+HB_INTERNAL uint16_t
+hb_indic_get_categories (hb_codepoint_t u);
+
+
+#endif /* HB_OT_SHAPER_INDIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
new file mode 100644
index 0000000000..e18bd75ef1
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh
@@ -0,0 +1,428 @@
+
+#line 1 "hb-ot-shaper-khmer-machine.rl"
+/*
+ * Copyright © 2011,2012 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_KHMER_MACHINE_HH
+#define HB_OT_SHAPER_KHMER_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define khmer_category() ot_shaper_var_u8_category() /* khmer_category_t */
+
+using khmer_category_t = unsigned;
+
+#define K_Cat(Cat) khmer_syllable_machine_ex_##Cat
+
+enum khmer_syllable_type_t {
+ khmer_consonant_syllable,
+ khmer_broken_cluster,
+ khmer_non_khmer_cluster,
+};
+
+
+#line 52 "hb-ot-shaper-khmer-machine.hh"
+#define khmer_syllable_machine_ex_C 1u
+#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define khmer_syllable_machine_ex_H 4u
+#define khmer_syllable_machine_ex_PLACEHOLDER 10u
+#define khmer_syllable_machine_ex_Ra 15u
+#define khmer_syllable_machine_ex_Robatic 25u
+#define khmer_syllable_machine_ex_V 2u
+#define khmer_syllable_machine_ex_VAbv 20u
+#define khmer_syllable_machine_ex_VBlw 21u
+#define khmer_syllable_machine_ex_VPre 22u
+#define khmer_syllable_machine_ex_VPst 23u
+#define khmer_syllable_machine_ex_Xgroup 26u
+#define khmer_syllable_machine_ex_Ygroup 27u
+#define khmer_syllable_machine_ex_ZWJ 6u
+#define khmer_syllable_machine_ex_ZWNJ 5u
+
+
+#line 70 "hb-ot-shaper-khmer-machine.hh"
+static const unsigned char _khmer_syllable_machine_trans_keys[] = {
+ 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
+ 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
+ 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 27u, 4u, 27u, 1u, 15u,
+ 4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u,
+ 4u, 27u, 1u, 15u, 4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u,
+ 4u, 27u, 4u, 27u, 5u, 26u, 0
+};
+
+static const char _khmer_syllable_machine_key_spans[] = {
+ 22, 22, 15, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 15, 22, 22,
+ 22, 22, 22, 22, 22, 27, 24, 15,
+ 24, 24, 1, 24, 24, 24, 24, 24,
+ 24, 15, 24, 24, 1, 24, 24, 24,
+ 24, 24, 22
+};
+
+static const short _khmer_syllable_machine_index_offsets[] = {
+ 0, 23, 46, 62, 85, 108, 131, 154,
+ 177, 200, 223, 246, 269, 292, 308, 331,
+ 354, 377, 400, 423, 446, 469, 497, 522,
+ 538, 563, 588, 590, 615, 640, 665, 690,
+ 715, 740, 756, 781, 806, 808, 833, 858,
+ 883, 908, 933
+};
+
+static const char _khmer_syllable_machine_indicies[] = {
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 3, 4, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 4, 0, 6, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 7, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 8, 0, 9, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0, 0, 0,
+ 10, 0, 9, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 10,
+ 0, 11, 11, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 12, 0,
+ 11, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 13, 4, 0, 15, 15,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 16, 14, 14,
+ 14, 14, 17, 18, 14, 15, 15, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 18, 19, 20, 20, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 20, 14, 15, 15, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 16, 14, 14, 14, 14,
+ 14, 18, 14, 21, 21, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 16, 14, 22, 22, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 23,
+ 14, 24, 24, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 16, 14, 14, 14, 14, 14, 25, 14,
+ 24, 24, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 25, 14, 26,
+ 26, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 16, 14,
+ 14, 14, 14, 14, 27, 14, 26, 26,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 27, 14, 29, 29, 28,
+ 30, 31, 31, 28, 28, 28, 13, 13,
+ 28, 28, 28, 29, 28, 28, 28, 28,
+ 16, 25, 27, 23, 28, 17, 18, 20,
+ 28, 33, 34, 34, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 2, 10, 12, 8, 32, 13, 4,
+ 5, 32, 35, 35, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 35, 32, 33, 36, 36, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 2, 10, 12, 8, 32, 3,
+ 4, 5, 32, 37, 38, 38, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 2, 10, 12, 8, 32,
+ 32, 4, 5, 32, 5, 32, 37, 6,
+ 6, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 8, 32, 32, 2, 5, 32, 37,
+ 7, 7, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 8, 5, 32,
+ 37, 39, 39, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 2, 32, 32, 8, 32, 32, 10, 5,
+ 32, 37, 40, 40, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 2, 10, 32, 8, 32, 32, 12,
+ 5, 32, 33, 38, 38, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 2, 10, 12, 8, 32, 32,
+ 4, 5, 32, 33, 38, 38, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 2, 10, 12, 8, 32,
+ 3, 4, 5, 32, 42, 42, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 42, 41, 30, 43, 43, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 16, 25, 27, 23,
+ 41, 17, 18, 20, 41, 44, 45, 45,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 16, 25, 27,
+ 23, 41, 41, 18, 20, 41, 20, 41,
+ 44, 21, 21, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 23, 41, 41, 16, 20,
+ 41, 44, 22, 22, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 23,
+ 20, 41, 44, 46, 46, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 16, 41, 41, 23, 41, 41,
+ 25, 20, 41, 44, 47, 47, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 16, 25, 41, 23, 41,
+ 41, 27, 20, 41, 30, 45, 45, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 16, 25, 27, 23,
+ 41, 41, 18, 20, 41, 15, 15, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 16, 48, 48, 48,
+ 48, 48, 18, 48, 0
+};
+
+static const char _khmer_syllable_machine_trans_targs[] = {
+ 21, 1, 27, 31, 25, 26, 4, 5,
+ 28, 7, 29, 9, 30, 32, 21, 12,
+ 37, 41, 35, 21, 36, 15, 16, 38,
+ 18, 39, 20, 40, 21, 22, 33, 42,
+ 21, 23, 10, 24, 0, 2, 3, 6,
+ 8, 21, 34, 11, 13, 14, 17, 19,
+ 21
+};
+
+static const char _khmer_syllable_machine_trans_actions[] = {
+ 1, 0, 2, 2, 2, 0, 0, 0,
+ 2, 0, 2, 0, 2, 2, 3, 0,
+ 2, 4, 4, 5, 0, 0, 0, 2,
+ 0, 2, 0, 2, 8, 2, 0, 9,
+ 10, 0, 0, 2, 0, 0, 0, 0,
+ 0, 11, 4, 0, 0, 0, 0, 0,
+ 12
+};
+
+static const char _khmer_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, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0
+};
+
+static const char _khmer_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, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0
+};
+
+static const short _khmer_syllable_machine_eof_trans[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 15, 20, 15, 15, 15,
+ 15, 15, 15, 15, 15, 0, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 49
+};
+
+static const int khmer_syllable_machine_start = 21;
+static const int khmer_syllable_machine_first_final = 21;
+static const int khmer_syllable_machine_error = -1;
+
+static const int khmer_syllable_machine_en_main = 21;
+
+
+#line 53 "hb-ot-shaper-khmer-machine.rl"
+
+
+
+#line 102 "hb-ot-shaper-khmer-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+inline void
+find_syllables_khmer (hb_buffer_t *buffer)
+{
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+#line 298 "hb-ot-shaper-khmer-machine.hh"
+ {
+ cs = khmer_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 122 "hb-ot-shaper-khmer-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 314 "hb-ot-shaper-khmer-machine.hh"
+ {
+ int _slen;
+ int _trans;
+ const unsigned char *_keys;
+ const char *_inds;
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
+ case 7:
+#line 1 "NONE"
+ {ts = p;}
+ break;
+#line 328 "hb-ot-shaper-khmer-machine.hh"
+ }
+
+ _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
+ _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
+
+ _slen = _khmer_syllable_machine_key_spans[cs];
+ _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
+ ( info[p].khmer_category()) <= _keys[1] ?
+ ( info[p].khmer_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+ cs = _khmer_syllable_machine_trans_targs[_trans];
+
+ if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
+ goto _again;
+
+ switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
+ case 2:
+#line 1 "NONE"
+ {te = p+1;}
+ break;
+ case 8:
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+ {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
+ break;
+ case 10:
+#line 96 "hb-ot-shaper-khmer-machine.rl"
+ {te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
+ break;
+ case 11:
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+ {te = p;p--;{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 12:
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+ {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
+ break;
+ case 1:
+#line 96 "hb-ot-shaper-khmer-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
+ break;
+ case 3:
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 5:
+#line 1 "NONE"
+ { switch( act ) {
+ case 2:
+ {{p = ((te))-1;} found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }
+ break;
+ case 3:
+ {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
+ break;
+ }
+ }
+ break;
+ case 4:
+#line 1 "NONE"
+ {te = p+1;}
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+ {act = 2;}
+ break;
+ case 9:
+#line 1 "NONE"
+ {te = p+1;}
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+ {act = 3;}
+ break;
+#line 398 "hb-ot-shaper-khmer-machine.hh"
+ }
+
+_again:
+ switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+ case 6:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 407 "hb-ot-shaper-khmer-machine.hh"
+ }
+
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ }
+
+#line 130 "hb-ot-shaper-khmer-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_KHMER_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc
index d7ec1632ea..e04d633195 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc
@@ -28,8 +28,8 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-khmer.hh"
-#include "hb-ot-shape-complex-khmer-machine.hh"
+#include "hb-ot-shaper-khmer-machine.hh"
+#include "hb-ot-shaper-indic.hh"
#include "hb-ot-layout.hh"
@@ -37,6 +37,7 @@
* Khmer shaper.
*/
+
static const hb_ot_map_feature_t
khmer_features[] =
{
@@ -79,6 +80,15 @@ enum {
KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */
};
+static inline void
+set_khmer_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+
+ info.khmer_category() = (khmer_category_t) (type & 0xFFu);
+}
+
static void
setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
@@ -110,7 +120,14 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
- for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++)
+ unsigned int i = 0;
+ for (; i < KHMER_BASIC_FEATURES; i++)
+ map->add_feature (khmer_features[i]);
+
+ /* https://github.com/harfbuzz/harfbuzz/issues/3531 */
+ map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
+
+ for (; i < KHMER_NUM_FEATURES; i++)
map->add_feature (khmer_features[i]);
}
@@ -180,6 +197,7 @@ setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
+ HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
find_syllables_khmer (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
@@ -223,11 +241,11 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
* the 'pref' OpenType feature applied to them.
* """
*/
- if (info[i].khmer_category() == OT_Coeng && num_coengs <= 2 && i + 1 < end)
+ if (info[i].khmer_category() == K_Cat(H) && num_coengs <= 2 && i + 1 < end)
{
num_coengs++;
- if (info[i + 1].khmer_category() == OT_Ra)
+ if (info[i + 1].khmer_category() == K_Cat(Ra))
{
for (unsigned int j = 0; j < 2; j++)
info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF];
@@ -255,7 +273,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
}
/* Reorder left matra piece. */
- else if (info[i].khmer_category() == OT_VPre)
+ else if (info[i].khmer_category() == K_Cat(VPre))
{
/* Move to the start. */
buffer->merge_clusters (start, i + 1);
@@ -294,8 +312,8 @@ reorder_khmer (const hb_ot_shape_plan_t *plan,
{
hb_syllabic_insert_dotted_circles (font, buffer,
khmer_broken_cluster,
- OT_DOTTEDCIRCLE,
- OT_Repha);
+ K_Cat(DOTTEDCIRCLE),
+ (unsigned) -1);
foreach_syllable (buffer, start, end)
reorder_syllable_khmer (plan, font->face, buffer, start, end);
@@ -342,7 +360,7 @@ compose_khmer (const hb_ot_shape_normalize_context_t *c,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer =
+const hb_ot_shaper_t _hb_ot_shaper_khmer =
{
collect_features_khmer,
override_features_khmer,
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
new file mode 100644
index 0000000000..b109708937
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh
@@ -0,0 +1,553 @@
+
+#line 1 "hb-ot-shaper-myanmar-machine.rl"
+/*
+ * Copyright © 2011,2012 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_MYANMAR_MACHINE_HH
+#define HB_OT_SHAPER_MYANMAR_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define myanmar_category() ot_shaper_var_u8_category() /* myanmar_category_t */
+#define myanmar_position() ot_shaper_var_u8_auxiliary() /* myanmar_position_t */
+
+using myanmar_category_t = unsigned;
+using myanmar_position_t = ot_position_t;
+
+#define M_Cat(Cat) myanmar_syllable_machine_ex_##Cat
+
+enum myanmar_syllable_type_t {
+ myanmar_consonant_syllable,
+ myanmar_broken_cluster,
+ myanmar_non_myanmar_cluster,
+};
+
+
+#line 54 "hb-ot-shaper-myanmar-machine.hh"
+#define myanmar_syllable_machine_ex_A 9u
+#define myanmar_syllable_machine_ex_As 32u
+#define myanmar_syllable_machine_ex_C 1u
+#define myanmar_syllable_machine_ex_CS 18u
+#define myanmar_syllable_machine_ex_DB 3u
+#define myanmar_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define myanmar_syllable_machine_ex_GB 10u
+#define myanmar_syllable_machine_ex_H 4u
+#define myanmar_syllable_machine_ex_IV 2u
+#define myanmar_syllable_machine_ex_MH 35u
+#define myanmar_syllable_machine_ex_ML 41u
+#define myanmar_syllable_machine_ex_MR 36u
+#define myanmar_syllable_machine_ex_MW 37u
+#define myanmar_syllable_machine_ex_MY 38u
+#define myanmar_syllable_machine_ex_PT 39u
+#define myanmar_syllable_machine_ex_Ra 15u
+#define myanmar_syllable_machine_ex_SM 8u
+#define myanmar_syllable_machine_ex_VAbv 20u
+#define myanmar_syllable_machine_ex_VBlw 21u
+#define myanmar_syllable_machine_ex_VPre 22u
+#define myanmar_syllable_machine_ex_VPst 23u
+#define myanmar_syllable_machine_ex_VS 40u
+#define myanmar_syllable_machine_ex_ZWJ 6u
+#define myanmar_syllable_machine_ex_ZWNJ 5u
+
+
+#line 81 "hb-ot-shaper-myanmar-machine.hh"
+static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
+ 1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
+ 5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u,
+ 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 41u,
+ 3u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
+ 5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 41u, 3u, 39u,
+ 3u, 39u, 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u,
+ 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 1u, 41u, 1u, 15u, 0
+};
+
+static const char _myanmar_syllable_machine_key_spans[] = {
+ 41, 39, 35, 4, 39, 37, 37, 35,
+ 35, 37, 37, 39, 35, 15, 37, 37,
+ 38, 37, 39, 39, 37, 39, 39, 39,
+ 39, 39, 35, 4, 39, 37, 37, 35,
+ 35, 37, 37, 39, 35, 15, 39, 37,
+ 37, 38, 37, 39, 39, 37, 39, 39,
+ 39, 39, 39, 39, 39, 41, 15
+};
+
+static const short _myanmar_syllable_machine_index_offsets[] = {
+ 0, 42, 82, 118, 123, 163, 201, 239,
+ 275, 311, 349, 387, 427, 463, 479, 517,
+ 555, 594, 632, 672, 712, 750, 790, 830,
+ 870, 910, 950, 986, 991, 1031, 1069, 1107,
+ 1143, 1179, 1217, 1255, 1295, 1331, 1347, 1387,
+ 1425, 1463, 1502, 1540, 1580, 1620, 1658, 1698,
+ 1738, 1778, 1818, 1858, 1898, 1938, 1980
+};
+
+static const char _myanmar_syllable_machine_indicies[] = {
+ 1, 1, 2, 3, 4, 4, 0, 5,
+ 6, 1, 1, 0, 0, 0, 7, 0,
+ 0, 8, 0, 9, 10, 11, 12, 0,
+ 0, 0, 0, 0, 0, 0, 0, 13,
+ 0, 0, 14, 15, 16, 17, 18, 19,
+ 20, 0, 22, 23, 24, 24, 21, 25,
+ 26, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 27, 28, 29, 30, 21,
+ 21, 21, 21, 21, 21, 21, 21, 31,
+ 21, 21, 32, 33, 34, 35, 36, 37,
+ 38, 21, 24, 24, 21, 25, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 30, 21, 21, 21,
+ 21, 21, 21, 21, 21, 39, 21, 21,
+ 21, 21, 21, 21, 36, 21, 24, 24,
+ 21, 25, 21, 22, 21, 24, 24, 21,
+ 25, 26, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 40, 21, 21, 30,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 41, 21, 21, 42, 21, 21, 21, 36,
+ 21, 41, 21, 22, 21, 24, 24, 21,
+ 25, 26, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 30,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 36,
+ 21, 43, 21, 24, 24, 21, 25, 36,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 44, 21,
+ 21, 21, 21, 21, 21, 36, 21, 24,
+ 24, 21, 25, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 44, 21, 21, 21, 21, 21,
+ 21, 36, 21, 24, 24, 21, 25, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 36, 21, 22,
+ 21, 24, 24, 21, 25, 26, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 40, 21, 21, 30, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 36, 21, 22, 21, 24,
+ 24, 21, 25, 26, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 40, 21,
+ 21, 30, 21, 21, 21, 21, 21, 21,
+ 21, 21, 41, 21, 21, 21, 21, 21,
+ 21, 36, 21, 22, 21, 24, 24, 21,
+ 25, 26, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 40, 21, 21, 30,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 41, 21, 21, 21, 21, 21, 21, 36,
+ 21, 41, 21, 24, 24, 21, 25, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 30, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 36, 21, 1,
+ 1, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 1, 21, 22,
+ 21, 24, 24, 21, 25, 26, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 27, 28, 21, 30, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 36, 21, 22, 21, 24,
+ 24, 21, 25, 26, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 28,
+ 21, 30, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 36, 21, 22, 21, 24, 24, 21,
+ 25, 26, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 27, 28, 29, 30,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 36,
+ 45, 21, 22, 21, 24, 24, 21, 25,
+ 26, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 27, 28, 29, 30, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 36, 21,
+ 22, 21, 24, 24, 21, 25, 26, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 27, 28, 29, 30, 21, 21, 21,
+ 21, 21, 21, 21, 21, 31, 21, 21,
+ 32, 33, 34, 35, 36, 21, 38, 21,
+ 22, 21, 24, 24, 21, 25, 26, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 27, 28, 29, 30, 21, 21, 21,
+ 21, 21, 21, 21, 21, 45, 21, 21,
+ 21, 21, 21, 21, 36, 21, 38, 21,
+ 22, 21, 24, 24, 21, 25, 26, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 27, 28, 29, 30, 21, 21, 21,
+ 21, 21, 21, 21, 21, 45, 21, 21,
+ 21, 21, 21, 21, 36, 21, 22, 21,
+ 24, 24, 21, 25, 26, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 27,
+ 28, 29, 30, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 32, 21,
+ 34, 21, 36, 21, 38, 21, 22, 21,
+ 24, 24, 21, 25, 26, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 27,
+ 28, 29, 30, 21, 21, 21, 21, 21,
+ 21, 21, 21, 45, 21, 21, 32, 21,
+ 21, 21, 36, 21, 38, 21, 22, 21,
+ 24, 24, 21, 25, 26, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 27,
+ 28, 29, 30, 21, 21, 21, 21, 21,
+ 21, 21, 21, 46, 21, 21, 32, 33,
+ 34, 21, 36, 21, 38, 21, 22, 21,
+ 24, 24, 21, 25, 26, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 27,
+ 28, 29, 30, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 32, 33,
+ 34, 21, 36, 21, 38, 21, 22, 23,
+ 24, 24, 21, 25, 26, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 27,
+ 28, 29, 30, 21, 21, 21, 21, 21,
+ 21, 21, 21, 31, 21, 21, 32, 33,
+ 34, 35, 36, 21, 38, 21, 48, 48,
+ 47, 5, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 12, 47, 47, 47, 47, 47, 47, 47,
+ 47, 49, 47, 47, 47, 47, 47, 47,
+ 18, 47, 48, 48, 47, 5, 47, 2,
+ 47, 48, 48, 47, 5, 6, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 50, 47, 47, 12, 47, 47, 47, 47,
+ 47, 47, 47, 47, 51, 47, 47, 52,
+ 47, 47, 47, 18, 47, 51, 47, 2,
+ 47, 48, 48, 47, 5, 6, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 12, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 18, 47, 53, 47, 48,
+ 48, 47, 5, 18, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 54, 47, 47, 47, 47, 47,
+ 47, 18, 47, 48, 48, 47, 5, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 54, 47,
+ 47, 47, 47, 47, 47, 18, 47, 48,
+ 48, 47, 5, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 18, 47, 2, 47, 48, 48, 47,
+ 5, 6, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 50, 47, 47, 12,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 18,
+ 47, 2, 47, 48, 48, 47, 5, 6,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 50, 47, 47, 12, 47, 47,
+ 47, 47, 47, 47, 47, 47, 51, 47,
+ 47, 47, 47, 47, 47, 18, 47, 2,
+ 47, 48, 48, 47, 5, 6, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 50, 47, 47, 12, 47, 47, 47, 47,
+ 47, 47, 47, 47, 51, 47, 47, 47,
+ 47, 47, 47, 18, 47, 51, 47, 48,
+ 48, 47, 5, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 12, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 18, 47, 55, 55, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 55, 47, 2, 3, 48, 48, 47,
+ 5, 6, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 9, 10, 11, 12,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 13, 47, 47, 14, 15, 16, 17, 18,
+ 19, 20, 47, 2, 47, 48, 48, 47,
+ 5, 6, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 9, 10, 47, 12,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 18,
+ 47, 2, 47, 48, 48, 47, 5, 6,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 10, 47, 12, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 18, 47, 2,
+ 47, 48, 48, 47, 5, 6, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 9, 10, 11, 12, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 18, 56, 47, 2, 47,
+ 48, 48, 47, 5, 6, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 9,
+ 10, 11, 12, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 18, 47, 2, 47, 48, 48,
+ 47, 5, 6, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 9, 10, 11,
+ 12, 47, 47, 47, 47, 47, 47, 47,
+ 47, 13, 47, 47, 14, 15, 16, 17,
+ 18, 47, 20, 47, 2, 47, 48, 48,
+ 47, 5, 6, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 9, 10, 11,
+ 12, 47, 47, 47, 47, 47, 47, 47,
+ 47, 56, 47, 47, 47, 47, 47, 47,
+ 18, 47, 20, 47, 2, 47, 48, 48,
+ 47, 5, 6, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 9, 10, 11,
+ 12, 47, 47, 47, 47, 47, 47, 47,
+ 47, 56, 47, 47, 47, 47, 47, 47,
+ 18, 47, 2, 47, 48, 48, 47, 5,
+ 6, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 9, 10, 11, 12, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 14, 47, 16, 47, 18, 47,
+ 20, 47, 2, 47, 48, 48, 47, 5,
+ 6, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 9, 10, 11, 12, 47,
+ 47, 47, 47, 47, 47, 47, 47, 56,
+ 47, 47, 14, 47, 47, 47, 18, 47,
+ 20, 47, 2, 47, 48, 48, 47, 5,
+ 6, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 9, 10, 11, 12, 47,
+ 47, 47, 47, 47, 47, 47, 47, 57,
+ 47, 47, 14, 15, 16, 47, 18, 47,
+ 20, 47, 2, 47, 48, 48, 47, 5,
+ 6, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 9, 10, 11, 12, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 14, 15, 16, 47, 18, 47,
+ 20, 47, 2, 3, 48, 48, 47, 5,
+ 6, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 9, 10, 11, 12, 47,
+ 47, 47, 47, 47, 47, 47, 47, 13,
+ 47, 47, 14, 15, 16, 17, 18, 47,
+ 20, 47, 22, 23, 24, 24, 21, 25,
+ 26, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 27, 28, 29, 30, 21,
+ 21, 21, 21, 21, 21, 21, 21, 58,
+ 21, 21, 32, 33, 34, 35, 36, 37,
+ 38, 21, 22, 59, 24, 24, 21, 25,
+ 26, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 27, 28, 29, 30, 21,
+ 21, 21, 21, 21, 21, 21, 21, 31,
+ 21, 21, 32, 33, 34, 35, 36, 21,
+ 38, 21, 1, 1, 2, 3, 48, 48,
+ 47, 5, 6, 1, 1, 47, 47, 47,
+ 1, 47, 47, 47, 47, 9, 10, 11,
+ 12, 47, 47, 47, 47, 47, 47, 47,
+ 47, 13, 47, 47, 14, 15, 16, 17,
+ 18, 19, 20, 47, 1, 1, 60, 60,
+ 60, 60, 60, 60, 60, 1, 1, 60,
+ 60, 60, 1, 60, 0
+};
+
+static const char _myanmar_syllable_machine_trans_targs[] = {
+ 0, 1, 26, 37, 0, 27, 29, 51,
+ 54, 39, 40, 41, 28, 43, 44, 46,
+ 47, 48, 30, 50, 45, 0, 2, 13,
+ 0, 3, 5, 14, 15, 16, 4, 18,
+ 19, 21, 22, 23, 6, 25, 20, 12,
+ 9, 10, 11, 7, 8, 17, 24, 0,
+ 0, 36, 33, 34, 35, 31, 32, 38,
+ 42, 49, 52, 53, 0
+};
+
+static const char _myanmar_syllable_machine_trans_actions[] = {
+ 3, 0, 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7,
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9
+};
+
+static const char _myanmar_syllable_machine_to_state_actions[] = {
+ 1, 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 _myanmar_syllable_machine_from_state_actions[] = {
+ 2, 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 _myanmar_syllable_machine_eof_trans[] = {
+ 0, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 22, 22, 48, 61
+};
+
+static const int myanmar_syllable_machine_start = 0;
+static const int myanmar_syllable_machine_first_final = 0;
+static const int myanmar_syllable_machine_error = -1;
+
+static const int myanmar_syllable_machine_en_main = 0;
+
+
+#line 55 "hb-ot-shaper-myanmar-machine.rl"
+
+
+
+#line 117 "hb-ot-shaper-myanmar-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+inline void
+find_syllables_myanmar (hb_buffer_t *buffer)
+{
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+#line 447 "hb-ot-shaper-myanmar-machine.hh"
+ {
+ cs = myanmar_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 137 "hb-ot-shaper-myanmar-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 463 "hb-ot-shaper-myanmar-machine.hh"
+ {
+ int _slen;
+ int _trans;
+ const unsigned char *_keys;
+ const char *_inds;
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
+ case 2:
+#line 1 "NONE"
+ {ts = p;}
+ break;
+#line 477 "hb-ot-shaper-myanmar-machine.hh"
+ }
+
+ _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
+ _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
+
+ _slen = _myanmar_syllable_machine_key_spans[cs];
+ _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
+ ( info[p].myanmar_category()) <= _keys[1] ?
+ ( info[p].myanmar_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+ cs = _myanmar_syllable_machine_trans_targs[_trans];
+
+ if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
+ goto _again;
+
+ switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
+ case 6:
+#line 110 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
+ break;
+ case 4:
+#line 111 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
+ break;
+ case 8:
+#line 112 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 3:
+#line 113 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
+ break;
+ case 5:
+#line 110 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
+ break;
+ case 7:
+#line 112 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 9:
+#line 113 "hb-ot-shaper-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
+ break;
+#line 523 "hb-ot-shaper-myanmar-machine.hh"
+ }
+
+_again:
+ switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
+ case 1:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 532 "hb-ot-shaper-myanmar-machine.hh"
+ }
+
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ }
+
+#line 145 "hb-ot-shaper-myanmar-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_MYANMAR_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc
index c7aa80a79a..1ccafbca7e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc
@@ -28,14 +28,16 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-myanmar.hh"
-#include "hb-ot-shape-complex-myanmar-machine.hh"
+#include "hb-ot-shaper-myanmar-machine.hh"
+#include "hb-ot-shaper-indic.hh"
+#include "hb-ot-layout.hh"
/*
* Myanmar shaper.
*/
+
static const hb_tag_t
myanmar_basic_features[] =
{
@@ -62,6 +64,40 @@ myanmar_other_features[] =
HB_TAG('p','s','t','s'),
};
+static inline void
+set_myanmar_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+
+ info.myanmar_category() = (myanmar_category_t) (type & 0xFFu);
+}
+
+
+static inline bool
+is_one_of_myanmar (const hb_glyph_info_t &info, unsigned int flags)
+{
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+ return !!(FLAG_UNSAFE (info.myanmar_category()) & flags);
+}
+
+/* Note:
+ *
+ * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
+ * cannot happen in a consonant syllable. The plus side however is, we can call the
+ * consonant syllable logic from the vowel syllable function and get it all right!
+ *
+ * Keep in sync with consonant_categories in the generator. */
+#define CONSONANT_FLAGS_MYANMAR (FLAG (M_Cat(C)) | FLAG (M_Cat(CS)) | FLAG (M_Cat(Ra)) | /* FLAG (M_Cat(CM)) | */ FLAG (M_Cat(IV)) | FLAG (M_Cat(GB)) | FLAG (M_Cat(DOTTEDCIRCLE)))
+
+static inline bool
+is_consonant_myanmar (const hb_glyph_info_t &info)
+{
+ return is_one_of_myanmar (info, CONSONANT_FLAGS_MYANMAR);
+}
+
+
static void
setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
@@ -92,6 +128,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (nullptr);
}
+ map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
@@ -105,8 +142,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;
@@ -119,6 +155,7 @@ setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
+ HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
find_syllables_myanmar (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
@@ -130,7 +167,7 @@ compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
int a = pa->myanmar_position();
int b = pb->myanmar_position();
- return a < b ? -1 : a == b ? 0 : +1;
+ return (int) a - (int) b;
}
@@ -149,9 +186,9 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
{
unsigned int limit = start;
if (start + 3 <= end &&
- info[start ].myanmar_category() == OT_Ra &&
- info[start+1].myanmar_category() == OT_As &&
- info[start+2].myanmar_category() == OT_H)
+ info[start ].myanmar_category() == M_Cat(Ra) &&
+ info[start+1].myanmar_category() == M_Cat(As) &&
+ info[start+2].myanmar_category() == M_Cat(H))
{
limit += 3;
base = start;
@@ -163,7 +200,7 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
base = limit;
for (unsigned int i = limit; i < end; i++)
- if (is_consonant (info[i]))
+ if (is_consonant_myanmar (info[i]))
{
base = i;
break;
@@ -188,39 +225,40 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
* Myanmar reordering! */
for (; i < end; i++)
{
- if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
+ if (info[i].myanmar_category() == M_Cat(MR)) /* Pre-base reordering */
{
info[i].myanmar_position() = POS_PRE_C;
continue;
}
- if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
+ if (info[i].myanmar_category() == M_Cat(VPre)) /* Left matra */
{
+ info[i].myanmar_position() = POS_PRE_M;
continue;
}
- if (info[i].myanmar_category() == OT_VS)
+ if (info[i].myanmar_category() == M_Cat(VS))
{
info[i].myanmar_position() = info[i - 1].myanmar_position();
continue;
}
- if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
+ if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == M_Cat(VBlw))
{
pos = POS_BELOW_C;
info[i].myanmar_position() = pos;
continue;
}
- if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
+ if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(A))
{
info[i].myanmar_position() = POS_BEFORE_SUB;
continue;
}
- if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
+ if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(VBlw))
{
info[i].myanmar_position() = pos;
continue;
}
- if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
+ if (pos == POS_BELOW_C && info[i].myanmar_category() != M_Cat(A))
{
pos = POS_AFTER_SUB;
info[i].myanmar_position() = pos;
@@ -248,7 +286,6 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
initial_reordering_consonant_syllable (buffer, start, end);
break;
- case myanmar_punctuation_cluster:
case myanmar_non_myanmar_cluster:
break;
}
@@ -263,7 +300,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan,
{
hb_syllabic_insert_dotted_circles (font, buffer,
myanmar_broken_cluster,
- OT_GB);
+ M_Cat(DOTTEDCIRCLE));
foreach_syllable (buffer, start, end)
reorder_syllable_myanmar (plan, font->face, buffer, start, end);
@@ -275,7 +312,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+const hb_ot_shaper_t _hb_ot_shaper_myanmar =
{
collect_features_myanmar,
nullptr, /* override_features */
@@ -297,7 +334,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
/* Ugly Zawgyi encoding.
* Disable all auto processing.
* https://github.com/harfbuzz/harfbuzz/issues/1162 */
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
+const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
{
nullptr, /* collect_features */
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
index 76092c7f38..a8e0d8e8c1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
@@ -26,7 +26,7 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-syllabic.hh"
+#include "hb-ot-shaper-syllabic.hh"
void
@@ -39,31 +39,18 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
{
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == broken_syllable_type)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
+ if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
return;
-
hb_codepoint_t dottedcircle_glyph;
if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
- dottedcircle.complex_var_u8_category() = dottedcircle_category;
+ dottedcircle.ot_shaper_var_u8_category() = dottedcircle_category;
if (dottedcircle_position != -1)
- dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position;
+ dottedcircle.ot_shaper_var_u8_auxiliary() = dottedcircle_position;
dottedcircle.codepoint = dottedcircle_glyph;
buffer->clear_output ();
@@ -87,7 +74,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
{
while (buffer->idx < buffer->len && buffer->successful &&
last_syllable == buffer->cur().syllable() &&
- buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
+ buffer->cur().ot_shaper_var_u8_category() == (unsigned) repha_category)
(void) buffer->next_glyph ();
}
@@ -99,5 +86,13 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
buffer->sync ();
}
+HB_INTERNAL void
+hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+}
+
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh
index b901a660d3..e8a15bb48a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh
@@ -22,12 +22,12 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
-#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+#ifndef HB_OT_SHAPER_SYLLABIC_HH
+#define HB_OT_SHAPER_SYLLABIC_HH
#include "hb.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
HB_INTERNAL void
@@ -38,5 +38,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
int repha_category = -1,
int dottedcircle_position = -1);
+HB_INTERNAL void
+hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
-#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
+#endif /* HB_OT_SHAPER_SYLLABIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc
index a1e27a83be..1280e7ed17 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc
@@ -28,7 +28,7 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
/* Thai / Lao shaper */
@@ -222,7 +222,7 @@ do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
hb_font_t *font)
{
-#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+#ifdef HB_NO_OT_SHAPER_THAI_FALLBACK
return;
#endif
@@ -279,7 +279,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
* to be what Uniscribe and other engines implement. According to Eric Muller:
*
* When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
- * NIKHAHIT backwards over any tone mark (0E48-0E4B).
+ * NIKHAHIT backwards over any above-base marks.
*
* <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
*
@@ -308,8 +308,8 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
* Nikhahit: U+0E4D U+0ECD
*
* Testing shows that Uniscribe reorder the following marks:
- * Thai: <0E31,0E34..0E37,0E47..0E4E>
- * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE>
+ * Thai: <0E31,0E34..0E37, 0E47..0E4E>
+ * Lao: <0EB1,0EB4..0EB7,0EBB,0EC8..0ECD>
*
* Note how the Lao versions are the same as Thai + 0x80.
*/
@@ -319,7 +319,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
#define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+#define IS_ABOVE_BASE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u, 0x0E3Bu, 0x0E3Bu))
buffer->clear_output ();
unsigned int count = buffer->len;
@@ -343,7 +343,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
/* Ok, let's see... */
unsigned int start = end - 2;
- while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+ while (start > 0 && IS_ABOVE_BASE_MARK (buffer->out_info[start - 1].codepoint))
start--;
if (start + 2 < end)
@@ -371,7 +371,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
do_thai_pua_shaping (plan, buffer, font);
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
+const hb_ot_shaper_t _hb_ot_shaper_thai =
{
nullptr, /* collect_features */
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
new file mode 100644
index 0000000000..65e65ff39d
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh
@@ -0,0 +1,931 @@
+
+#line 1 "hb-ot-shaper-use-machine.rl"
+/*
+ * Copyright © 2015 Mozilla Foundation.
+ * Copyright © 2015 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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_USE_MACHINE_HH
+#define HB_OT_SHAPER_USE_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-syllabic.hh"
+
+/* buffer var allocations */
+#define use_category() ot_shaper_var_u8_category()
+
+#define USE(Cat) use_syllable_machine_ex_##Cat
+
+enum use_syllable_type_t {
+ use_virama_terminated_cluster,
+ use_sakot_terminated_cluster,
+ use_standard_cluster,
+ use_number_joiner_terminated_cluster,
+ use_numeral_cluster,
+ use_symbol_cluster,
+ use_hieroglyph_cluster,
+ use_broken_cluster,
+ use_non_cluster,
+};
+
+
+#line 57 "hb-ot-shaper-use-machine.hh"
+#define use_syllable_machine_ex_B 1u
+#define use_syllable_machine_ex_CGJ 6u
+#define use_syllable_machine_ex_CMAbv 31u
+#define use_syllable_machine_ex_CMBlw 32u
+#define use_syllable_machine_ex_CS 43u
+#define use_syllable_machine_ex_FAbv 24u
+#define use_syllable_machine_ex_FBlw 25u
+#define use_syllable_machine_ex_FMAbv 45u
+#define use_syllable_machine_ex_FMBlw 46u
+#define use_syllable_machine_ex_FMPst 47u
+#define use_syllable_machine_ex_FPst 26u
+#define use_syllable_machine_ex_G 49u
+#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 53u
+#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
+#define use_syllable_machine_ex_MPre 30u
+#define use_syllable_machine_ex_MPst 29u
+#define use_syllable_machine_ex_N 4u
+#define use_syllable_machine_ex_O 0u
+#define use_syllable_machine_ex_R 18u
+#define use_syllable_machine_ex_SB 51u
+#define use_syllable_machine_ex_SE 52u
+#define use_syllable_machine_ex_SMAbv 41u
+#define use_syllable_machine_ex_SMBlw 42u
+#define use_syllable_machine_ex_SUB 11u
+#define use_syllable_machine_ex_Sk 48u
+#define use_syllable_machine_ex_VAbv 33u
+#define use_syllable_machine_ex_VBlw 34u
+#define use_syllable_machine_ex_VMAbv 37u
+#define use_syllable_machine_ex_VMBlw 38u
+#define use_syllable_machine_ex_VMPre 23u
+#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 101 "hb-ot-shaper-use-machine.hh"
+static const unsigned char _use_syllable_machine_trans_keys[] = {
+ 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u,
+ 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u,
+ 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u,
+ 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 41u, 42u, 42u, 42u, 11u, 53u, 11u, 53u,
+ 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u,
+ 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u,
+ 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u,
+ 13u, 13u, 4u, 4u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u,
+ 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u,
+ 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u,
+ 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u,
+ 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u,
+ 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u,
+ 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 4u, 4u, 13u, 13u,
+ 1u, 53u, 11u, 53u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u,
+ 0
+};
+
+static const char _use_syllable_machine_key_spans[] = {
+ 54, 43, 43, 53, 26, 24, 23, 22,
+ 2, 1, 25, 25, 25, 1, 25, 32,
+ 31, 31, 31, 42, 31, 42, 42, 42,
+ 43, 1, 48, 43, 2, 1, 43, 43,
+ 53, 26, 24, 23, 22, 2, 1, 25,
+ 25, 25, 1, 25, 32, 31, 31, 31,
+ 42, 31, 42, 42, 42, 43, 1, 48,
+ 1, 1, 43, 43, 53, 26, 24, 23,
+ 22, 2, 1, 25, 25, 25, 1, 25,
+ 32, 31, 31, 31, 42, 31, 42, 42,
+ 42, 43, 1, 48, 43, 43, 53, 26,
+ 24, 23, 22, 2, 1, 25, 25, 25,
+ 1, 25, 32, 31, 31, 31, 42, 31,
+ 42, 42, 42, 43, 1, 48, 1, 1,
+ 53, 43, 2, 1, 5, 3, 4, 3
+};
+
+static const short _use_syllable_machine_index_offsets[] = {
+ 0, 55, 99, 143, 197, 224, 249, 273,
+ 296, 299, 301, 327, 353, 379, 381, 407,
+ 440, 472, 504, 536, 579, 611, 654, 697,
+ 740, 784, 786, 835, 879, 882, 884, 928,
+ 972, 1026, 1053, 1078, 1102, 1125, 1128, 1130,
+ 1156, 1182, 1208, 1210, 1236, 1269, 1301, 1333,
+ 1365, 1408, 1440, 1483, 1526, 1569, 1613, 1615,
+ 1664, 1666, 1668, 1712, 1756, 1810, 1837, 1862,
+ 1886, 1909, 1912, 1914, 1940, 1966, 1992, 1994,
+ 2020, 2053, 2085, 2117, 2149, 2192, 2224, 2267,
+ 2310, 2353, 2397, 2399, 2448, 2492, 2536, 2590,
+ 2617, 2642, 2666, 2689, 2692, 2694, 2720, 2746,
+ 2772, 2774, 2800, 2833, 2865, 2897, 2929, 2972,
+ 3004, 3047, 3090, 3133, 3177, 3179, 3228, 3230,
+ 3232, 3286, 3330, 3333, 3335, 3341, 3345, 3350
+};
+
+static const unsigned 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, 16, 17, 18,
+ 19, 20, 21, 22, 2, 23, 24, 25,
+ 2, 26, 27, 28, 29, 30, 31, 32,
+ 29, 33, 2, 34, 2, 35, 2, 37,
+ 38, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52,
+ 36, 53, 54, 55, 36, 56, 57, 36,
+ 58, 59, 60, 61, 58, 36, 36, 36,
+ 36, 62, 36, 37, 38, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 49,
+ 49, 50, 51, 52, 36, 53, 54, 55,
+ 36, 36, 36, 36, 58, 59, 60, 61,
+ 58, 36, 36, 36, 36, 62, 36, 37,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 40, 41, 42,
+ 43, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 53, 54, 55, 36, 36,
+ 36, 36, 36, 59, 60, 61, 63, 36,
+ 36, 36, 36, 40, 36, 40, 41, 42,
+ 43, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 53, 54, 55, 36, 36,
+ 36, 36, 36, 59, 60, 61, 63, 36,
+ 41, 42, 43, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 59, 60, 61,
+ 36, 42, 43, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 59, 60, 61,
+ 36, 43, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 59, 60, 61, 36,
+ 59, 60, 36, 60, 36, 41, 42, 43,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 53, 54, 55, 36, 36, 36,
+ 36, 36, 59, 60, 61, 63, 36, 41,
+ 42, 43, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 54, 55, 36,
+ 36, 36, 36, 36, 59, 60, 61, 63,
+ 36, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 64, 36, 41, 42, 43,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 59, 60, 61, 63, 36, 39,
+ 40, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 50, 51, 52, 36, 53, 54,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 36, 36, 36, 40, 36,
+ 40, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 50, 51, 52, 36, 53, 54,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 36, 36, 36, 40, 36,
+ 40, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 36, 51, 52, 36, 53, 54,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 36, 36, 36, 40, 36,
+ 40, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 36, 36, 52, 36, 53, 54,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 36, 36, 36, 40, 36,
+ 65, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 39, 40, 41, 42, 43, 36,
+ 45, 46, 36, 36, 36, 50, 51, 52,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 36, 59, 60, 61, 63, 36, 36, 36,
+ 36, 40, 36, 40, 41, 42, 43, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 36, 59, 60, 61, 63, 36, 36, 36,
+ 36, 40, 36, 65, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 39, 40, 41,
+ 42, 43, 36, 36, 46, 36, 36, 36,
+ 50, 51, 52, 36, 53, 54, 55, 36,
+ 36, 36, 36, 36, 59, 60, 61, 63,
+ 36, 36, 36, 36, 40, 36, 65, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 39, 40, 41, 42, 43, 36, 36, 36,
+ 36, 36, 36, 50, 51, 52, 36, 53,
+ 54, 55, 36, 36, 36, 36, 36, 59,
+ 60, 61, 63, 36, 36, 36, 36, 40,
+ 36, 65, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 39, 40, 41, 42, 43,
+ 44, 45, 46, 36, 36, 36, 50, 51,
+ 52, 36, 53, 54, 55, 36, 36, 36,
+ 36, 36, 59, 60, 61, 63, 36, 36,
+ 36, 36, 40, 36, 37, 38, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 36, 49, 50, 51, 52, 36, 53, 54,
+ 55, 36, 36, 36, 36, 58, 59, 60,
+ 61, 58, 36, 36, 36, 36, 62, 36,
+ 37, 36, 37, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 40, 41, 42, 43, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 53, 54,
+ 55, 36, 36, 36, 36, 36, 59, 60,
+ 61, 63, 36, 37, 38, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 36, 53, 54, 55,
+ 36, 36, 36, 36, 58, 59, 60, 61,
+ 58, 36, 36, 36, 36, 62, 36, 56,
+ 57, 36, 57, 36, 67, 68, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77,
+ 1, 78, 79, 80, 81, 66, 82, 83,
+ 84, 66, 66, 66, 66, 85, 86, 87,
+ 88, 89, 66, 66, 66, 66, 90, 66,
+ 67, 68, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 78, 79, 80,
+ 81, 66, 82, 83, 84, 66, 66, 66,
+ 66, 85, 86, 87, 88, 89, 66, 66,
+ 66, 66, 90, 66, 67, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 70, 71, 72, 73, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 82, 83, 84, 66, 66, 66, 66, 66,
+ 86, 87, 88, 91, 66, 66, 66, 66,
+ 70, 66, 70, 71, 72, 73, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 82, 83, 84, 66, 66, 66, 66, 66,
+ 86, 87, 88, 91, 66, 71, 72, 73,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 86, 87, 88, 66, 72, 73,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 86, 87, 88, 66, 73, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 86, 87, 88, 66, 86, 87, 66,
+ 87, 66, 71, 72, 73, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 82,
+ 83, 84, 66, 66, 66, 66, 66, 86,
+ 87, 88, 91, 66, 71, 72, 73, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 83, 84, 66, 66, 66, 66,
+ 66, 86, 87, 88, 91, 66, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 93, 92, 71, 72, 73, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 86,
+ 87, 88, 91, 66, 69, 70, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 79,
+ 80, 81, 66, 82, 83, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 66, 66, 66, 70, 66, 70, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 79,
+ 80, 81, 66, 82, 83, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 66, 66, 66, 70, 66, 70, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 66,
+ 80, 81, 66, 82, 83, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 66, 66, 66, 70, 66, 70, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 66,
+ 66, 81, 66, 82, 83, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 66, 66, 66, 70, 66, 94, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 69,
+ 70, 71, 72, 73, 66, 75, 76, 66,
+ 66, 66, 79, 80, 81, 66, 82, 83,
+ 84, 66, 66, 66, 66, 66, 86, 87,
+ 88, 91, 66, 66, 66, 66, 70, 66,
+ 70, 71, 72, 73, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 82, 83,
+ 84, 66, 66, 66, 66, 66, 86, 87,
+ 88, 91, 66, 66, 66, 66, 70, 66,
+ 94, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 69, 70, 71, 72, 73, 66,
+ 66, 76, 66, 66, 66, 79, 80, 81,
+ 66, 82, 83, 84, 66, 66, 66, 66,
+ 66, 86, 87, 88, 91, 66, 66, 66,
+ 66, 70, 66, 94, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 69, 70, 71,
+ 72, 73, 66, 66, 66, 66, 66, 66,
+ 79, 80, 81, 66, 82, 83, 84, 66,
+ 66, 66, 66, 66, 86, 87, 88, 91,
+ 66, 66, 66, 66, 70, 66, 94, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 69, 70, 71, 72, 73, 74, 75, 76,
+ 66, 66, 66, 79, 80, 81, 66, 82,
+ 83, 84, 66, 66, 66, 66, 66, 86,
+ 87, 88, 91, 66, 66, 66, 66, 70,
+ 66, 67, 68, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 66, 78, 79,
+ 80, 81, 66, 82, 83, 84, 66, 66,
+ 66, 66, 85, 86, 87, 88, 89, 66,
+ 66, 66, 66, 90, 66, 67, 95, 67,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 70, 71, 72,
+ 73, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 82, 83, 84, 66, 66,
+ 66, 66, 66, 86, 87, 88, 91, 66,
+ 97, 96, 3, 98, 99, 100, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 66, 115, 116,
+ 117, 66, 56, 57, 66, 118, 119, 120,
+ 88, 121, 66, 66, 66, 66, 122, 66,
+ 99, 100, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 111, 111, 112, 113,
+ 114, 66, 115, 116, 117, 66, 66, 66,
+ 66, 118, 119, 120, 88, 121, 66, 66,
+ 66, 66, 122, 66, 99, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 102, 103, 104, 105, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 115, 116, 117, 66, 66, 66, 66, 66,
+ 119, 120, 88, 123, 66, 66, 66, 66,
+ 102, 66, 102, 103, 104, 105, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 115, 116, 117, 66, 66, 66, 66, 66,
+ 119, 120, 88, 123, 66, 103, 104, 105,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 119, 120, 88, 66, 104, 105,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 119, 120, 88, 66, 105, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 119, 120, 88, 66, 119, 120, 66,
+ 120, 66, 103, 104, 105, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 115,
+ 116, 117, 66, 66, 66, 66, 66, 119,
+ 120, 88, 123, 66, 103, 104, 105, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 116, 117, 66, 66, 66, 66,
+ 66, 119, 120, 88, 123, 66, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 124, 92, 103, 104, 105, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 119,
+ 120, 88, 123, 66, 101, 102, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 112,
+ 113, 114, 66, 115, 116, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 66, 66, 66, 102, 66, 102, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 112,
+ 113, 114, 66, 115, 116, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 66, 66, 66, 102, 66, 102, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 66,
+ 113, 114, 66, 115, 116, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 66, 66, 66, 102, 66, 102, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 66,
+ 66, 114, 66, 115, 116, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 66, 66, 66, 102, 66, 125, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 101,
+ 102, 103, 104, 105, 66, 107, 108, 66,
+ 66, 66, 112, 113, 114, 66, 115, 116,
+ 117, 66, 66, 66, 66, 66, 119, 120,
+ 88, 123, 66, 66, 66, 66, 102, 66,
+ 102, 103, 104, 105, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 115, 116,
+ 117, 66, 66, 66, 66, 66, 119, 120,
+ 88, 123, 66, 66, 66, 66, 102, 66,
+ 125, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 101, 102, 103, 104, 105, 66,
+ 66, 108, 66, 66, 66, 112, 113, 114,
+ 66, 115, 116, 117, 66, 66, 66, 66,
+ 66, 119, 120, 88, 123, 66, 66, 66,
+ 66, 102, 66, 125, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 101, 102, 103,
+ 104, 105, 66, 66, 66, 66, 66, 66,
+ 112, 113, 114, 66, 115, 116, 117, 66,
+ 66, 66, 66, 66, 119, 120, 88, 123,
+ 66, 66, 66, 66, 102, 66, 125, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 66, 66, 66, 112, 113, 114, 66, 115,
+ 116, 117, 66, 66, 66, 66, 66, 119,
+ 120, 88, 123, 66, 66, 66, 66, 102,
+ 66, 99, 100, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 66, 111, 112,
+ 113, 114, 66, 115, 116, 117, 66, 66,
+ 66, 66, 118, 119, 120, 88, 121, 66,
+ 66, 66, 66, 122, 66, 99, 95, 99,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 102, 103, 104,
+ 105, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 115, 116, 117, 66, 66,
+ 66, 66, 66, 119, 120, 88, 123, 66,
+ 99, 100, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 66, 115, 116, 117, 66, 66, 66,
+ 66, 118, 119, 120, 88, 121, 66, 66,
+ 66, 66, 122, 66, 5, 6, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 19, 19, 20, 21, 22, 126, 23, 24,
+ 25, 126, 126, 126, 126, 29, 30, 31,
+ 32, 29, 126, 126, 126, 126, 35, 126,
+ 5, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 10, 11,
+ 12, 13, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 23, 24, 25, 126,
+ 126, 126, 126, 126, 30, 31, 32, 127,
+ 126, 126, 126, 126, 10, 126, 10, 11,
+ 12, 13, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 23, 24, 25, 126,
+ 126, 126, 126, 126, 30, 31, 32, 127,
+ 126, 11, 12, 13, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 30, 31,
+ 32, 126, 12, 13, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 30, 31,
+ 32, 126, 13, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 30, 31, 32,
+ 126, 30, 31, 126, 31, 126, 11, 12,
+ 13, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 23, 24, 25, 126, 126,
+ 126, 126, 126, 30, 31, 32, 127, 126,
+ 11, 12, 13, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 24, 25,
+ 126, 126, 126, 126, 126, 30, 31, 32,
+ 127, 126, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 128, 126, 11, 12,
+ 13, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 30, 31, 32, 127, 126,
+ 9, 10, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 20, 21, 22, 126, 23,
+ 24, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 126, 126, 126, 10,
+ 126, 10, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 20, 21, 22, 126, 23,
+ 24, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 126, 126, 126, 10,
+ 126, 10, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 126, 21, 22, 126, 23,
+ 24, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 126, 126, 126, 10,
+ 126, 10, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 126, 126, 22, 126, 23,
+ 24, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 126, 126, 126, 10,
+ 126, 129, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 9, 10, 11, 12, 13,
+ 126, 15, 16, 126, 126, 126, 20, 21,
+ 22, 126, 23, 24, 25, 126, 126, 126,
+ 126, 126, 30, 31, 32, 127, 126, 126,
+ 126, 126, 10, 126, 10, 11, 12, 13,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 23, 24, 25, 126, 126, 126,
+ 126, 126, 30, 31, 32, 127, 126, 126,
+ 126, 126, 10, 126, 129, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 9, 10,
+ 11, 12, 13, 126, 126, 16, 126, 126,
+ 126, 20, 21, 22, 126, 23, 24, 25,
+ 126, 126, 126, 126, 126, 30, 31, 32,
+ 127, 126, 126, 126, 126, 10, 126, 129,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 9, 10, 11, 12, 13, 126, 126,
+ 126, 126, 126, 126, 20, 21, 22, 126,
+ 23, 24, 25, 126, 126, 126, 126, 126,
+ 30, 31, 32, 127, 126, 126, 126, 126,
+ 10, 126, 129, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 9, 10, 11, 12,
+ 13, 14, 15, 16, 126, 126, 126, 20,
+ 21, 22, 126, 23, 24, 25, 126, 126,
+ 126, 126, 126, 30, 31, 32, 127, 126,
+ 126, 126, 126, 10, 126, 5, 6, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 126, 19, 20, 21, 22, 126, 23,
+ 24, 25, 126, 126, 126, 126, 29, 30,
+ 31, 32, 29, 126, 126, 126, 126, 35,
+ 126, 5, 126, 5, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 10, 11, 12, 13, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 23,
+ 24, 25, 126, 126, 126, 126, 126, 30,
+ 31, 32, 127, 126, 130, 126, 7, 126,
+ 1, 126, 126, 126, 1, 126, 126, 126,
+ 126, 126, 5, 6, 7, 126, 126, 126,
+ 126, 126, 126, 126, 126, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 126, 23, 24, 25, 126,
+ 26, 27, 126, 29, 30, 31, 32, 29,
+ 126, 126, 126, 126, 35, 126, 5, 6,
+ 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 126,
+ 23, 24, 25, 126, 126, 126, 126, 29,
+ 30, 31, 32, 29, 126, 126, 126, 126,
+ 35, 126, 26, 27, 126, 27, 126, 1,
+ 131, 131, 131, 1, 131, 133, 132, 33,
+ 132, 33, 133, 132, 133, 132, 33, 132,
+ 34, 132, 0
+};
+
+static const char _use_syllable_machine_trans_targs[] = {
+ 1, 30, 0, 56, 58, 85, 86, 110,
+ 112, 98, 87, 88, 89, 90, 102, 104,
+ 105, 106, 113, 107, 99, 100, 101, 93,
+ 94, 95, 114, 115, 116, 108, 91, 92,
+ 0, 117, 119, 109, 0, 2, 3, 15,
+ 4, 5, 6, 7, 19, 21, 22, 23,
+ 27, 24, 16, 17, 18, 10, 11, 12,
+ 28, 29, 25, 8, 9, 0, 26, 13,
+ 14, 20, 0, 31, 32, 44, 33, 34,
+ 35, 36, 48, 50, 51, 52, 53, 45,
+ 46, 47, 39, 40, 41, 54, 37, 38,
+ 0, 54, 55, 42, 0, 43, 49, 0,
+ 0, 57, 0, 59, 60, 72, 61, 62,
+ 63, 64, 76, 78, 79, 80, 84, 81,
+ 73, 74, 75, 67, 68, 69, 82, 65,
+ 66, 82, 83, 70, 71, 77, 0, 96,
+ 97, 103, 111, 0, 0, 118
+};
+
+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, 0,
+ 4, 0, 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,
+ 0, 0, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 0, 0,
+ 9, 10, 0, 0, 11, 0, 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, 0, 0, 15, 0,
+ 0, 0, 0, 16, 17, 0
+};
+
+static const char _use_syllable_machine_to_state_actions[] = {
+ 1, 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, 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[] = {
+ 2, 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, 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, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 93, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 96, 67,
+ 97, 99, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 93, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 96, 67, 67, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 132, 133, 133, 133
+};
+
+static const int use_syllable_machine_start = 0;
+static const int use_syllable_machine_first_final = 0;
+static const int use_syllable_machine_error = -1;
+
+static const int use_syllable_machine_en_main = 0;
+
+
+#line 58 "hb-ot-shaper-use-machine.rl"
+
+
+
+#line 182 "hb-ot-shaper-use-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
+ for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+
+template <typename Iter>
+struct machine_index_t :
+ hb_iter_with_fallback_t<machine_index_t<Iter>,
+ typename Iter::item_t>
+{
+ machine_index_t (const Iter& it) : it (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;
+
+ typename Iter::item_t __item__ () const { return *it; }
+ typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
+ unsigned __len__ () const { return it.len (); }
+ void __next__ () { ++it; }
+ void __forward__ (unsigned n) { it += n; }
+ void __prev__ () { --it; }
+ void __rewind__ (unsigned n) { it -= n; }
+
+ void operator = (unsigned n)
+ {
+ 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
+{
+ template <typename Iter,
+ hb_requires (hb_is_iterable (Iter))>
+ machine_index_t<hb_iter_type<Iter>>
+ operator () (Iter&& it) const
+ { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
+}
+HB_FUNCOBJ (machine_index);
+
+
+
+static bool
+not_ccs_default_ignorable (const hb_glyph_info_t &i)
+{ return i.use_category() != USE(CGJ); }
+
+static inline void
+find_syllables_use (hb_buffer_t *buffer)
+{
+ hb_glyph_info_t *info = buffer->info;
+ auto p =
+ + hb_iter (info, buffer->len)
+ | hb_enumerate
+ | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
+ hb_second)
+ | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
+ {
+ if (p.second.use_category() == USE(ZWNJ))
+ for (unsigned i = p.first + 1; i < buffer->len; ++i)
+ if (not_ccs_default_ignorable (info[i]))
+ return !_hb_glyph_info_is_unicode_mark (&info[i]);
+ return true;
+ })
+ | hb_enumerate
+ | machine_index
+ ;
+ auto pe = p + p.len ();
+ auto eof = +pe;
+ auto ts = +p;
+ auto te = +p;
+ unsigned int act HB_UNUSED;
+ int cs;
+
+#line 784 "hb-ot-shaper-use-machine.hh"
+ {
+ cs = use_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 282 "hb-ot-shaper-use-machine.rl"
+
+
+ unsigned int syllable_serial = 1;
+
+#line 797 "hb-ot-shaper-use-machine.hh"
+ {
+ int _slen;
+ int _trans;
+ const unsigned char *_keys;
+ const unsigned char *_inds;
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ switch ( _use_syllable_machine_from_state_actions[cs] ) {
+ case 2:
+#line 1 "NONE"
+ {ts = p;}
+ break;
+#line 811 "hb-ot-shaper-use-machine.hh"
+ }
+
+ _keys = _use_syllable_machine_trans_keys + (cs<<1);
+ _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
+
+ _slen = _use_syllable_machine_key_spans[cs];
+ _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
+ ( (*p).second.second.use_category()) <= _keys[1] ?
+ ( (*p).second.second.use_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+ cs = _use_syllable_machine_trans_targs[_trans];
+
+ if ( _use_syllable_machine_trans_actions[_trans] == 0 )
+ goto _again;
+
+ switch ( _use_syllable_machine_trans_actions[_trans] ) {
+ case 9:
+#line 172 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_standard_cluster); }}
+ break;
+ case 6:
+#line 175 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_symbol_cluster); }}
+ break;
+ case 4:
+#line 177 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 3:
+#line 178 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_non_cluster); }}
+ break;
+ case 11:
+#line 171 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
+ break;
+ case 7:
+#line 172 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_standard_cluster); }}
+ break;
+ case 14:
+#line 173 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
+ break;
+ case 13:
+#line 174 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_numeral_cluster); }}
+ break;
+ case 5:
+#line 175 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_symbol_cluster); }}
+ break;
+ case 17:
+#line 176 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
+ break;
+ case 15:
+#line 177 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+ break;
+ case 16:
+#line 178 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_non_cluster); }}
+ break;
+ 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 170 "hb-ot-shaper-use-machine.rl"
+ {act = 1;}
+ break;
+ case 10:
+#line 1 "NONE"
+ {te = p+1;}
+#line 171 "hb-ot-shaper-use-machine.rl"
+ {act = 2;}
+ break;
+#line 901 "hb-ot-shaper-use-machine.hh"
+ }
+
+_again:
+ switch ( _use_syllable_machine_to_state_actions[cs] ) {
+ case 1:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 910 "hb-ot-shaper-use-machine.hh"
+ }
+
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = _use_syllable_machine_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ }
+
+#line 287 "hb-ot-shaper-use-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_USE_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
index ea627cd27e..5aa025fb4c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
@@ -37,12 +37,12 @@
* UnicodeData.txt does not have a header.
*/
-#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
+#ifndef HB_OT_SHAPER_USE_TABLE_HH
+#define HB_OT_SHAPER_USE_TABLE_HH
#include "hb.hh"
-#include "hb-ot-shape-complex-use-machine.hh"
+#include "hb-ot-shaper-use-machine.hh"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -53,6 +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 */
@@ -246,7 +247,7 @@ static const uint8_t use_table[] = {
/* 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, 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,
+ /* 0DC0 */ B, B, B, B, B, B, B, WJ, WJ, WJ, HVM, 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,
@@ -606,7 +607,7 @@ static const uint8_t use_table[] = {
/* 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, WJ, WJ, CMAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS,
+ /* 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 4304
@@ -1531,6 +1532,7 @@ hb_use_get_category (hb_glyph_info_t info)
#undef GB
#undef H
#undef HN
+#undef HVM
#undef IS
#undef J
#undef N
@@ -1566,5 +1568,5 @@ hb_use_get_category (hb_glyph_info_t info)
#undef VMPre
-#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */
+#endif /* HB_OT_SHAPER_USE_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
index 1d13c8a126..60394ed4d8 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
@@ -30,11 +30,11 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-use-machine.hh"
-#include "hb-ot-shape-complex-use-table.hh"
-#include "hb-ot-shape-complex-arabic.hh"
-#include "hb-ot-shape-complex-arabic-joining-list.hh"
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-use-machine.hh"
+#include "hb-ot-shaper-use-table.hh"
+#include "hb-ot-shaper-arabic.hh"
+#include "hb-ot-shaper-arabic-joining-list.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
/*
@@ -133,6 +133,7 @@ collect_features_use (hb_ot_shape_planner_t *plan)
map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (reorder_use);
+ map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
/* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
@@ -297,6 +298,7 @@ setup_syllables_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
+ HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
find_syllables_use (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
@@ -349,7 +351,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(IS)) &&
+ return (info.use_category() == USE(H) || info.use_category() == USE(HVM) || info.use_category() == USE(IS)) &&
!_hb_glyph_info_ligated (&info);
}
@@ -480,7 +482,7 @@ compose_use (const hb_ot_shape_normalize_context_t *c,
}
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
+const hb_ot_shaper_t _hb_ot_shaper_use =
{
collect_features_use,
nullptr, /* override_features */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
index d2cca105a4..be4ac813b1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
@@ -18,7 +18,7 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
static void
_output_dotted_circle (hb_buffer_t *buffer)
@@ -39,7 +39,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
-#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS
return;
#endif
if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.hh
index d9082d4ead..5a7ee1b0f2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.hh
@@ -24,16 +24,16 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
-#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
+#ifndef HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH
+#define HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH
#include "hb.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
HB_INTERNAL void
_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font);
-#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */
+#endif /* HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
index 8012a9ae94..b823bf003c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper.hh
@@ -24,8 +24,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_HH
-#define HB_OT_SHAPE_COMPLEX_HH
+#ifndef HB_OT_SHAPER_HH
+#define HB_OT_SHAPER_HH
#include "hb.hh"
@@ -34,12 +34,12 @@
#include "hb-ot-shape-normalize.hh"
-/* buffer var allocations, used by complex shapers */
-#define complex_var_u8_category() var2.u8[2]
-#define complex_var_u8_auxiliary() var2.u8[3]
+/* buffer var allocations, used by all OT shapers */
+#define ot_shaper_var_u8_category() var2.u8[2]
+#define ot_shaper_var_u8_auxiliary() var2.u8[3]
-#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
+#define HB_OT_SHAPE_MAX_COMBINING_MARKS 32
enum hb_ot_shape_zero_width_marks_type_t {
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
@@ -49,22 +49,22 @@ enum hb_ot_shape_zero_width_marks_type_t {
/* Master OT shaper list */
-#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
- HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
- HB_COMPLEX_SHAPER_IMPLEMENT (default) \
- HB_COMPLEX_SHAPER_IMPLEMENT (dumber) \
- HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
- HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
- HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
- HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \
- HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
- HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \
- HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
- HB_COMPLEX_SHAPER_IMPLEMENT (use) \
+#define HB_OT_SHAPERS_IMPLEMENT_SHAPERS \
+ HB_OT_SHAPER_IMPLEMENT (arabic) \
+ HB_OT_SHAPER_IMPLEMENT (default) \
+ HB_OT_SHAPER_IMPLEMENT (dumber) \
+ HB_OT_SHAPER_IMPLEMENT (hangul) \
+ HB_OT_SHAPER_IMPLEMENT (hebrew) \
+ HB_OT_SHAPER_IMPLEMENT (indic) \
+ HB_OT_SHAPER_IMPLEMENT (khmer) \
+ HB_OT_SHAPER_IMPLEMENT (myanmar) \
+ HB_OT_SHAPER_IMPLEMENT (myanmar_zawgyi) \
+ HB_OT_SHAPER_IMPLEMENT (thai) \
+ HB_OT_SHAPER_IMPLEMENT (use) \
/* ^--- Add new shapers here; keep sorted. */
-struct hb_ot_complex_shaper_t
+struct hb_ot_shaper_t
{
/* collect_features()
* Called during shape_plan().
@@ -168,18 +168,18 @@ struct hb_ot_complex_shaper_t
bool fallback_position;
};
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
-HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+#define HB_OT_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_shaper_t _hb_ot_shaper_##name;
+HB_OT_SHAPERS_IMPLEMENT_SHAPERS
+#undef HB_OT_SHAPER_IMPLEMENT
-static inline const hb_ot_complex_shaper_t *
-hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
+static inline const hb_ot_shaper_t *
+hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
{
switch ((hb_tag_t) planner->props.script)
{
default:
- return &_hb_ot_complex_shaper_default;
+ return &_hb_ot_shaper_default;
/* Unicode-1.1 additions */
@@ -195,28 +195,28 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
planner->props.script == HB_SCRIPT_ARABIC) &&
HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
- return &_hb_ot_complex_shaper_arabic;
+ return &_hb_ot_shaper_arabic;
else
- return &_hb_ot_complex_shaper_default;
+ return &_hb_ot_shaper_default;
/* Unicode-1.1 additions */
case HB_SCRIPT_THAI:
case HB_SCRIPT_LAO:
- return &_hb_ot_complex_shaper_thai;
+ return &_hb_ot_shaper_thai;
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
- return &_hb_ot_complex_shaper_hangul;
+ return &_hb_ot_shaper_hangul;
/* Unicode-1.1 additions */
case HB_SCRIPT_HEBREW:
- return &_hb_ot_complex_shaper_hebrew;
+ return &_hb_ot_shaper_hebrew;
/* Unicode-1.1 additions */
@@ -230,9 +230,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_TAMIL:
case HB_SCRIPT_TELUGU:
- /* Unicode-3.0 additions */
- case HB_SCRIPT_SINHALA:
-
/* If the designer designed the font for the 'DFLT' script,
* (or we ended up arbitrarily pick 'latn'), use the default shaper.
* Otherwise, use the specific shaper.
@@ -240,14 +237,14 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
* If it's indy3 tag, send to USE. */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
- return &_hb_ot_complex_shaper_default;
+ return &_hb_ot_shaper_default;
else if ((planner->map.chosen_script[0] & 0x000000FF) == '3')
- return &_hb_ot_complex_shaper_use;
+ return &_hb_ot_shaper_use;
else
- return &_hb_ot_complex_shaper_indic;
+ return &_hb_ot_shaper_indic;
case HB_SCRIPT_KHMER:
- return &_hb_ot_complex_shaper_khmer;
+ return &_hb_ot_shaper_khmer;
case HB_SCRIPT_MYANMAR:
/* If the designer designed the font for the 'DFLT' script,
@@ -260,16 +257,16 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n') ||
planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
- return &_hb_ot_complex_shaper_default;
+ return &_hb_ot_shaper_default;
else
- return &_hb_ot_complex_shaper_myanmar;
+ return &_hb_ot_shaper_myanmar;
#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
case HB_SCRIPT_MYANMAR_ZAWGYI:
/* https://github.com/harfbuzz/harfbuzz/issues/1162 */
- return &_hb_ot_complex_shaper_myanmar_zawgyi;
+ return &_hb_ot_shaper_myanmar_zawgyi;
/* Unicode-2.0 additions */
@@ -277,7 +274,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-3.0 additions */
case HB_SCRIPT_MONGOLIAN:
- //case HB_SCRIPT_SINHALA:
+ case HB_SCRIPT_SINHALA:
/* Unicode-3.2 additions */
case HB_SCRIPT_BUHID:
@@ -390,11 +387,11 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
* GSUB/GPOS needed, so there may be no scripts found! */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
- return &_hb_ot_complex_shaper_default;
+ return &_hb_ot_shaper_default;
else
- return &_hb_ot_complex_shaper_use;
+ return &_hb_ot_shaper_use;
}
}
-#endif /* HB_OT_SHAPE_COMPLEX_HH */
+#endif /* HB_OT_SHAPER_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
index 5261783277..9394b90ee6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
@@ -13,1612 +13,1617 @@
#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 */
- {"ajt", HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> 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 [collection] -> 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 [collection] -> 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 [collection] */
- {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */
- {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */
- {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */
- {"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 [collection] */
- {"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 [collection] */
- {"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 */
- {"chm", HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */
- {"chm", HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */
- {"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 [collection] -> Creoles */
- {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */
- {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */
-/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> 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 [collection] -> 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 [collection] != 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 [collection] */
- {"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 */
- {"ike", HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik 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] */
- {"iu", HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */
- {"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 [collection] */
-/*{"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) (retired code) != 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 [collection] != 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) */
- {"mo", HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
- {"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 [collection] != 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 [collection] */
- {"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 [collection] */
- {"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) */
- {"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 [collection] != 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 */
- {"sh", HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */
- {"sh", HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */
- {"sh", HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */
- {"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 [collection] != Slavey */
- {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */
- {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */
- {"smd", HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */
- {"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 */
- {"snb", HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */
- {"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 [collection] != 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 [collection] != 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 */
};
+#ifndef HB_NO_LANGUAGE_LONG
+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 */
+};
+#endif
+
/**
* hb_ot_tags_from_complex_language:
* @lang_str: a BCP 47 language tag to convert.
@@ -1633,75 +1638,81 @@ static const LangTag ot_languages[] = {
*
* Return value: Whether any language systems were retrieved.
**/
-static bool
+static inline bool
hb_ot_tags_from_complex_language (const char *lang_str,
const char *limit,
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"))
+ if (limit - lang_str >= 7)
{
- /* 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"))
- {
- /* 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':
@@ -1714,14 +1725,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;
@@ -1734,14 +1745,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;
@@ -1754,14 +1765,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;
@@ -1774,14 +1785,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;
@@ -1794,14 +1805,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;
@@ -1814,14 +1825,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;
@@ -1834,14 +1845,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;
@@ -1854,14 +1865,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;
@@ -1874,112 +1885,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 */
@@ -1987,7 +1998,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 */
@@ -1995,7 +2006,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;
@@ -2009,7 +2020,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 */
@@ -2017,7 +2028,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 */
@@ -2025,7 +2036,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;
@@ -2039,7 +2050,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 */
@@ -2047,7 +2058,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 */
@@ -2055,7 +2066,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;
@@ -2069,7 +2080,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 */
@@ -2077,7 +2088,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 */
@@ -2085,7 +2096,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;
@@ -2099,7 +2110,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 */
@@ -2107,7 +2118,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 */
@@ -2115,7 +2126,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;
@@ -2129,7 +2140,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 */
@@ -2137,7 +2148,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 */
@@ -2145,7 +2156,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;
@@ -2159,7 +2170,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 */
@@ -2167,7 +2178,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 */
@@ -2175,7 +2186,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;
@@ -2189,7 +2200,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 */
@@ -2197,7 +2208,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 */
@@ -2205,7 +2216,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;
@@ -2219,7 +2230,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 */
@@ -2228,14 +2239,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;
@@ -2248,21 +2259,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 */
@@ -2270,7 +2281,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 */
@@ -2278,7 +2289,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;
@@ -2292,7 +2303,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 */
@@ -2301,14 +2312,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;
@@ -2321,14 +2332,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;
@@ -2341,28 +2352,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 */
@@ -2370,7 +2381,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 */
@@ -2378,7 +2389,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;
@@ -2392,7 +2403,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 */
@@ -2400,7 +2411,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 */
@@ -2408,7 +2419,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;
@@ -2422,7 +2433,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 */
@@ -2460,7 +2471,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 */
@@ -2469,14 +2480,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;
@@ -2489,14 +2500,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 */
@@ -2504,7 +2515,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 */
@@ -2512,7 +2523,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;
@@ -2526,7 +2537,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 */
@@ -2534,7 +2545,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 */
@@ -2543,14 +2554,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;
@@ -2563,14 +2574,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 */
@@ -2578,7 +2589,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 */
@@ -2586,7 +2597,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;
@@ -2600,7 +2611,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 */
@@ -2624,7 +2635,7 @@ hb_ot_tags_from_complex_language (const char *lang_str,
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 */
unsigned int i;
@@ -2639,14 +2650,14 @@ hb_ot_tags_from_complex_language (const char *lang_str,
}
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;
@@ -2659,14 +2670,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 */
@@ -2674,7 +2685,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 */
@@ -2682,7 +2693,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;
@@ -2696,7 +2707,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 */
@@ -2705,7 +2716,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 */
@@ -2714,14 +2725,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;
@@ -2741,14 +2752,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 */
@@ -2763,7 +2774,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 */
@@ -2771,7 +2782,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;
@@ -2785,7 +2796,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 */
@@ -2809,7 +2820,7 @@ hb_ot_tags_from_complex_language (const char *lang_str,
* Return value: The #hb_language_t corresponding to the BCP 47 language tag,
* or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
**/
-static hb_language_t
+static inline hb_language_t
hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
{
switch (tag)
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index f50be97ad3..ce5cdce98b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -189,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); }
@@ -265,16 +263,19 @@ hb_ot_tags_from_language (const char *lang_str,
unsigned int *count,
hb_tag_t *tags)
{
- const char *s;
- unsigned int tag_idx;
+#ifndef HB_NO_LANGUAGE_LONG
/* Check for matches of multiple subtags. */
if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags))
return;
+#endif
/* Find a language matching in the first component. */
- s = strchr (lang_str, '-');
+#ifndef HB_NO_LANGUAGE_LONG
+ const char *s; s = strchr (lang_str, '-');
+#endif
{
+#ifndef HB_NO_LANGUAGE_LONG
if (s && limit - lang_str >= 6)
{
const char *extlang_end = strchr (s + 1, '-');
@@ -283,17 +284,42 @@ 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))
+#endif
+ 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);
+ }
+#ifndef HB_NO_LANGUAGE_LONG
+ else if (first_len == 3)
{
+ ot_languages = ot_languages3;
+ ot_languages_len = ARRAY_LENGTH (ot_languages3);
+ }
+#endif
+
+ hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len);
+
+ static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */
+ unsigned tag_idx = last_tag_idx.get_relaxed ();
+
+ 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.set_relaxed (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;
@@ -301,6 +327,7 @@ hb_ot_tags_from_language (const char *lang_str,
}
}
+#ifndef HB_NO_LANGUAGE_LONG
if (!s)
s = lang_str + strlen (lang_str);
if (s - lang_str == 3) {
@@ -309,6 +336,7 @@ hb_ot_tags_from_language (const char *lang_str,
*count = 1;
return;
}
+#endif
*count = 0;
}
@@ -453,15 +481,29 @@ hb_ot_tag_to_language (hb_tag_t tag)
if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
return nullptr;
+#ifndef HB_NO_LANGUAGE_LONG
{
hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag);
if (disambiguated_tag != HB_LANGUAGE_INVALID)
return disambiguated_tag;
}
+#endif
- 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);
+ }
+#ifndef HB_NO_LANGUAGE_LONG
+ 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);
+ }
+#endif
/* 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
@@ -557,16 +599,28 @@ 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_languages[i].cmp (&ot_languages[i - 1]);
+ int c = ot_languages2[i].cmp (&ot_languages2[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_languages2 not sorted at index %d: %08x %d %08x\n",
+ i, ot_languages2[i-1].language, c, ot_languages2[i].language);
abort();
}
}
+#ifndef HB_NO_LANGUAGE_LONG
+ for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++)
+ {
+ int c = ot_languages3[i].cmp (&ot_languages3[i - 1]);
+ if (c > 0)
+ {
+ 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();
+ }
+ }
+#endif
}
int
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
index e066558683..c5c476bc0e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
@@ -213,7 +213,7 @@ struct fvar
if (!axis_index) axis_index = &i;
*axis_index = HB_OT_VAR_NO_AXIS_INDEX;
auto axes = get_axes ();
- return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true);
+ return axes.lfind (tag, axis_index) && ((void) axes[*axis_index].get_axis_deprecated (info), true);
}
#endif
bool
@@ -221,7 +221,7 @@ struct fvar
{
unsigned i;
auto axes = get_axes ();
- return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true);
+ return axes.lfind (tag, &i) && ((void) axes[i].get_axis_info (i, info), true);
}
int normalize_axis_value (unsigned int axis_index, float v) const
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
index 618cec08fb..bf1039d1d6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
@@ -45,9 +45,10 @@ struct contour_point_t
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
- uint8_t flag;
- float x, y;
- bool is_end_point;
+ float x = 0.f;
+ float y = 0.f;
+ uint8_t flag = 0;
+ bool is_end_point = false;
};
struct contour_point_vector_t : hb_vector_t<contour_point_t>
@@ -55,16 +56,24 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
void extend (const hb_array_t<contour_point_t> &a)
{
unsigned int old_len = length;
- resize (old_len + a.length);
- for (unsigned int i = 0; i < a.length; i++)
- (*this)[old_len + i] = a[i];
+ if (unlikely (!resize (old_len + a.length)))
+ return;
+ auto arrayZ = this->arrayZ + old_len;
+ unsigned count = a.length;
+ for (unsigned int i = 0; i < count; i++)
+ arrayZ[i] = a.arrayZ[i];
}
void transform (const float (&matrix)[4])
{
- for (unsigned int i = 0; i < length; i++)
+ if (matrix[0] == 1.f && matrix[1] == 0.f &&
+ matrix[2] == 0.f && matrix[3] == 1.f)
+ return;
+ auto arrayZ = this->arrayZ;
+ unsigned count = length;
+ for (unsigned i = 0; i < count; i++)
{
- contour_point_t &p = (*this)[i];
+ contour_point_t &p = arrayZ[i];
float x_ = p.x * matrix[0] + p.y * matrix[2];
p.y = p.x * matrix[1] + p.y * matrix[3];
p.x = x_;
@@ -73,8 +82,12 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
void translate (const contour_point_t& delta)
{
- for (unsigned int i = 0; i < length; i++)
- (*this)[i].translate (delta);
+ if (delta.x == 0.f && delta.y == 0.f)
+ return;
+ auto arrayZ = this->arrayZ;
+ unsigned count = length;
+ for (unsigned i = 0; i < count; i++)
+ arrayZ[i].translate (delta);
}
};
@@ -89,7 +102,7 @@ struct TupleVariationHeader
const TupleVariationHeader &get_next (unsigned axis_count) const
{ return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
- float calculate_scalar (const int *coords, unsigned int coord_count,
+ float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples) const
{
hb_array_t<const F2DOT14> peak_tuple;
@@ -208,7 +221,7 @@ struct GlyphVariationData
{
const HBUINT8 *base = &(var_data+var_data->data);
const HBUINT8 *p = base;
- if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
+ if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
data_offset = p - base;
}
return true;
@@ -258,7 +271,7 @@ struct GlyphVariationData
static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<unsigned int> &points /* OUT */,
- const hb_bytes_t &bytes)
+ const HBUINT8 *end)
{
enum packed_point_flag_t
{
@@ -266,21 +279,21 @@ struct GlyphVariationData
POINT_RUN_COUNT_MASK = 0x7F
};
- if (unlikely (!bytes.check_range (p))) return false;
+ if (unlikely (p + 1 > end)) return false;
uint16_t count = *p++;
if (count & POINTS_ARE_WORDS)
{
- if (unlikely (!bytes.check_range (p))) return false;
+ if (unlikely (p + 1 > end)) return false;
count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
}
- points.resize (count);
+ if (unlikely (!points.resize (count))) return false;
unsigned int n = 0;
uint16_t i = 0;
while (i < count)
{
- if (unlikely (!bytes.check_range (p))) return false;
+ if (unlikely (p + 1 > end)) return false;
uint16_t j;
uint8_t control = *p++;
uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
@@ -288,8 +301,7 @@ struct GlyphVariationData
{
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
- return false;
+ if (unlikely (p + HBUINT16::static_size > end)) return false;
n += *(const HBUINT16 *)p;
points[i] = n;
p += HBUINT16::static_size;
@@ -299,7 +311,7 @@ struct GlyphVariationData
{
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.check_range (p))) return false;
+ if (unlikely (p + 1 > end)) return false;
n += *p++;
points[i] = n;
}
@@ -311,7 +323,7 @@ struct GlyphVariationData
static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<int> &deltas /* IN/OUT */,
- const hb_bytes_t &bytes)
+ const HBUINT8 *end)
{
enum packed_delta_flag_t
{
@@ -324,7 +336,7 @@ struct GlyphVariationData
unsigned int count = deltas.length;
while (i < count)
{
- if (unlikely (!bytes.check_range (p))) return false;
+ if (unlikely (p + 1 > end)) return false;
uint8_t control = *p++;
unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
unsigned int j;
@@ -334,16 +346,14 @@ struct GlyphVariationData
else if (control & DELTAS_ARE_WORDS)
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
- return false;
+ if (unlikely (p + HBUINT16::static_size > end)) return false;
deltas[i] = *(const HBINT16 *) p;
p += HBUINT16::static_size;
}
else
for (j = 0; j < run_count && i < count; j++, i++)
{
- if (unlikely (!bytes.check_range (p)))
- return false;
+ if (unlikely (p + 1 > end)) return false;
deltas[i] = *(const HBINT8 *) p++;
}
if (j < run_count)
@@ -390,13 +400,10 @@ 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 variation data */
@@ -482,7 +489,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 +499,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; }
@@ -503,19 +515,17 @@ struct gvar
~accelerator_t () { table.destroy (); }
private:
- struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
- struct y_getter { static float get (const contour_point_t &p) { return p.y; } };
- template <typename T>
static float infer_delta (const hb_array_t<contour_point_t> points,
const hb_array_t<contour_point_t> deltas,
- unsigned int target, unsigned int prev, unsigned int next)
+ unsigned int target, unsigned int prev, unsigned int next,
+ float contour_point_t::*m)
{
- float target_val = T::get (points[target]);
- float prev_val = T::get (points[prev]);
- float next_val = T::get (points[next]);
- float prev_delta = T::get (deltas[prev]);
- float next_delta = T::get (deltas[next]);
+ float target_val = points[target].*m;
+ float prev_val = points[prev].*m;
+ float next_val = points[next].*m;
+ float prev_delta = deltas[prev].*m;
+ float next_delta = deltas[next].*m;
if (prev_val == next_val)
return (prev_delta == next_delta) ? prev_delta : 0.f;
@@ -526,7 +536,7 @@ struct gvar
/* linear interpolation */
float r = (target_val - prev_val) / (next_val - prev_val);
- return (1.f - r) * prev_delta + r * next_delta;
+ return prev_delta + r * (next_delta - prev_delta);
}
static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
@@ -536,8 +546,7 @@ struct gvar
bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
const hb_array_t<contour_point_t> points) const
{
- /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */
- if (!font->num_coords || font->num_coords != table->axisCount) return true;
+ if (!font->num_coords) return true;
if (unlikely (glyph >= table->glyphCount)) return true;
@@ -551,21 +560,25 @@ struct gvar
/* Save original points for inferred delta calculation */
contour_point_vector_t orig_points;
- orig_points.resize (points.length);
+ if (unlikely (!orig_points.resize (points.length))) return false;
for (unsigned int i = 0; i < orig_points.length; i++)
- orig_points[i] = points[i];
+ orig_points.arrayZ[i] = points.arrayZ[i];
contour_point_vector_t deltas; /* flag is used to indicate referenced point */
- deltas.resize (points.length);
+ if (unlikely (!deltas.resize (points.length))) return false;
hb_vector_t<unsigned> end_points;
for (unsigned i = 0; i < points.length; ++i)
if (points[i].is_end_point)
end_points.push (i);
- int *coords = font->coords;
- unsigned num_coords = font->num_coords;
+ auto coords = hb_array (font->coords, font->num_coords);
+ unsigned num_coords = table->axisCount;
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+
+ hb_vector_t<unsigned int> private_indices;
+ hb_vector_t<int> x_deltas;
+ hb_vector_t<int> y_deltas;
do
{
float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
@@ -575,33 +588,30 @@ struct gvar
if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
return false;
- hb_bytes_t bytes ((const char *) p, length);
- hb_vector_t<unsigned int> private_indices;
+ const HBUINT8 *end = p + length;
+
bool has_private_points = iterator.current_tuple->has_private_points ();
if (has_private_points &&
- !GlyphVariationData::unpack_points (p, private_indices, bytes))
+ !GlyphVariationData::unpack_points (p, private_indices, end))
return false;
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;
- hb_vector_t<int> x_deltas;
- x_deltas.resize (num_deltas);
- if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
- return false;
- hb_vector_t<int> y_deltas;
- y_deltas.resize (num_deltas);
- if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
- return false;
+ if (unlikely (!x_deltas.resize (num_deltas))) return false;
+ if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
+ if (unlikely (!y_deltas.resize (num_deltas))) return false;
+ if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
for (unsigned int i = 0; i < deltas.length; i++)
deltas[i].init ();
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = apply_to_all ? i : indices[i];
- deltas[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */
- deltas[pt_index].x += x_deltas[i] * scalar;
- deltas[pt_index].y += y_deltas[i] * scalar;
+ if (unlikely (pt_index >= deltas.length)) continue;
+ deltas.arrayZ[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ deltas.arrayZ[pt_index].x += x_deltas.arrayZ[i] * scalar;
+ deltas.arrayZ[pt_index].y += y_deltas.arrayZ[i] * scalar;
}
/* infer deltas for unreferenced points */
@@ -645,20 +655,20 @@ struct gvar
{
i = next_index (i, start_point, end_point);
if (i == next) break;
- deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
- deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+ deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::x);
+ deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::y);
if (--unref_count == 0) goto no_more_gaps;
}
}
-no_more_gaps:
+ no_more_gaps:
start_point = end_point + 1;
}
/* apply specified / inferred deltas to points */
for (unsigned int i = 0; i < points.length; i++)
{
- points[i].x += deltas[i].x;
- points[i].y += deltas[i].y;
+ points.arrayZ[i].x += deltas.arrayZ[i].x;
+ points.arrayZ[i].y += deltas.arrayZ[i].y;
}
} while (iterator.move_to_next ());
@@ -696,7 +706,7 @@ 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 {
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
index e9d90352f0..56efcdbee9 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
@@ -319,10 +319,15 @@ struct HVARVVAR
hvar_plan.index_map_plans.as_array ()));
}
- float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const
+ float get_advance_var (hb_codepoint_t glyph,
+ hb_font_t *font,
+ VariationStore::cache_t *store_cache = nullptr) const
{
uint32_t varidx = (this+advMap).map (glyph);
- return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
+ return (this+varStore).get_delta (varidx,
+ font->coords,
+ font->num_coords,
+ store_cache);
}
float get_side_bearing_var (hb_codepoint_t glyph,
@@ -335,7 +340,7 @@ struct HVARVVAR
bool has_side_bearing_deltas () const { return lsbMap && rsbMap; }
- protected:
+ public:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
Offset32To<VariationStore>
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 2a9e75c45b..683a441ec3 100644
--- a/thirdparty/harfbuzz/src/hb-repacker.hh
+++ b/thirdparty/harfbuzz/src/hb-repacker.hh
@@ -32,1074 +32,18 @@
#include "hb-priority-queue.hh"
#include "hb-serialize.hh"
#include "hb-vector.hh"
+#include "graph/graph.hh"
+#include "graph/serialize.hh"
+
+using graph::graph_t;
/*
* For a detailed writeup on the overflow resolution algorithm see:
* docs/repacker.md
*/
-struct graph_t
-{
- struct vertex_t
- {
- hb_serialize_context_t::object_t obj;
- int64_t distance = 0 ;
- int64_t space = 0 ;
- hb_vector_t<unsigned> parents;
- unsigned start = 0;
- unsigned end = 0;
- unsigned priority = 0;
-
- bool is_shared () const
- {
- return parents.length > 1;
- }
-
- unsigned incoming_edges () const
- {
- return parents.length;
- }
-
- void remove_parent (unsigned parent_index)
- {
- for (unsigned i = 0; i < parents.length; i++)
- {
- if (parents[i] != parent_index) continue;
- parents.remove (i);
- break;
- }
- }
-
- void remap_parents (const hb_vector_t<unsigned>& id_map)
- {
- for (unsigned i = 0; i < parents.length; i++)
- parents[i] = id_map[parents[i]];
- }
-
- void remap_parent (unsigned old_index, unsigned new_index)
- {
- for (unsigned i = 0; i < parents.length; i++)
- {
- if (parents[i] == old_index)
- parents[i] = new_index;
- }
- }
-
- bool is_leaf () const
- {
- return !obj.real_links.length && !obj.virtual_links.length;
- }
-
- bool raise_priority ()
- {
- if (has_max_priority ()) return false;
- priority++;
- return true;
- }
-
- bool has_max_priority () const {
- return priority >= 3;
- }
-
- int64_t modified_distance (unsigned order) const
- {
- // TODO(garretrieger): once priority is high enough, should try
- // setting distance = 0 which will force to sort immediately after
- // it's parent where possible.
-
- int64_t modified_distance =
- hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
- if (has_max_priority ()) {
- modified_distance = 0;
- }
- return (modified_distance << 18) | (0x003FFFF & order);
- }
-
- int64_t distance_modifier () const
- {
- if (!priority) return 0;
- int64_t table_size = obj.tail - obj.head;
-
- if (priority == 1)
- return -table_size / 2;
-
- return -table_size;
- }
- };
-
- struct overflow_record_t
- {
- unsigned parent;
- unsigned child;
- };
-
- /*
- * A topological sorting of an object graph. Ordered
- * in reverse serialization order (first object in the
- * serialization is at the end of the list). This matches
- * the 'packed' object stack used internally in the
- * serializer
- */
- template<typename T>
- graph_t (const T& objects)
- : parents_invalid (true),
- distance_invalid (true),
- positions_invalid (true),
- successful (true)
- {
- num_roots_for_space_.push (1);
- bool removed_nil = false;
- for (unsigned i = 0; i < objects.length; i++)
- {
- // TODO(grieger): check all links point to valid objects.
-
- // If this graph came from a serialization buffer object 0 is the
- // nil object. We don't need it for our purposes here so drop it.
- if (i == 0 && !objects[i])
- {
- removed_nil = true;
- continue;
- }
-
- vertex_t* v = vertices_.push ();
- if (check_success (!vertices_.in_error ()))
- v->obj = *objects[i];
- if (!removed_nil) continue;
- // Fix indices to account for removed nil object.
- for (auto& l : v->obj.all_links_writer ()) {
- l.objidx--;
- }
- }
- }
-
- ~graph_t ()
- {
- vertices_.fini ();
- }
-
- bool in_error () const
- {
- return !successful ||
- vertices_.in_error () ||
- num_roots_for_space_.in_error ();
- }
-
- const vertex_t& root () const
- {
- return vertices_[root_idx ()];
- }
-
- unsigned root_idx () const
- {
- // Object graphs are in reverse order, the first object is at the end
- // of the vector. Since the graph is topologically sorted it's safe to
- // assume the first object has no incoming edges.
- return vertices_.length - 1;
- }
-
- const hb_serialize_context_t::object_t& object(unsigned i) const
- {
- return vertices_[i].obj;
- }
-
- /*
- * serialize graph into the provided serialization buffer.
- */
- hb_blob_t* serialize () const
- {
- hb_vector_t<char> buffer;
- size_t size = serialized_length ();
- if (!buffer.alloc (size)) {
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
- return nullptr;
- }
- hb_serialize_context_t c((void *) buffer, size);
-
- c.start_serialize<void> ();
- for (unsigned i = 0; i < vertices_.length; i++) {
- c.push ();
-
- size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
- char* start = c.allocate_size <char> (size);
- if (!start) {
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
- return nullptr;
- }
-
- memcpy (start, vertices_[i].obj.head, size);
-
- // Only real links needs to be serialized.
- for (const auto& link : vertices_[i].obj.real_links)
- serialize_link (link, start, &c);
-
- // All duplications are already encoded in the graph, so don't
- // enable sharing during packing.
- c.pop_pack (false);
- }
- c.end_serialize ();
-
- if (c.in_error ()) {
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
- c.errors);
- return nullptr;
- }
-
- return c.copy_blob ();
- }
-
- /*
- * 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 ();
- }
-
- /*
- * Generates a new topological sorting of graph ordered by the shortest
- * distance to each node.
- */
- void sort_shortest_distance ()
- {
- positions_invalid = true;
-
- if (vertices_.length <= 1) {
- // Graph of 1 or less doesn't need sorting.
- return;
- }
-
- update_distances ();
-
- hb_priority_queue_t 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.insert (root ().modified_distance (0), root_idx ());
- int new_id = root_idx ();
- unsigned order = 1;
- while (!queue.in_error () && !queue.is_empty ())
- {
- unsigned next_id = queue.pop_minimum().second;
-
- 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]))
- // Add the order that the links were encountered to the priority.
- // This ensures that ties between priorities objects are broken in a consistent
- // way. More specifically this is set up so that if a set of objects have the same
- // distance they'll be added to the topological order in the order that they are
- // referenced from the parent object.
- queue.insert (vertices_[link.objidx].modified_distance (order++),
- 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 ();
- }
-
- /*
- * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
- */
- bool assign_32bit_spaces ()
- {
- unsigned root_index = root_idx ();
- hb_set_t visited;
- hb_set_t roots;
- for (unsigned i = 0; i <= root_index; i++)
- {
- // Only real links can form 32 bit spaces
- for (auto& l : vertices_[i].obj.real_links)
- {
- if (l.width == 4 && !l.is_signed)
- {
- roots.add (l.objidx);
- find_subgraph (l.objidx, visited);
- }
- }
- }
-
- // Mark everything not in the subgraphs of 32 bit roots as visited.
- // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs.
- visited.invert ();
-
- if (!roots) return false;
-
- 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);
- for (unsigned root : connected_roots)
- {
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
- vertices_[root].space = next_space;
- num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1;
- distance_invalid = true;
- positions_invalid = true;
- }
-
- // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space
- // into the 32 bit space as needed, instead of using isolation.
- }
-
-
-
- return true;
- }
-
- /*
- * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph
- * that originate from outside of the subgraph will be removed by duplicating the linked to
- * object.
- *
- * Indices stored in roots will be updated if any of the roots are duplicated to new indices.
- */
- bool isolate_subgraph (hb_set_t& roots)
- {
- update_parents ();
- hb_hashmap_t<unsigned, unsigned> subgraph;
-
- // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
- // set the subgraph incoming edge count to match all of root_idx's incoming edges
- hb_set_t parents;
- for (unsigned root_idx : roots)
- {
- subgraph.set (root_idx, wide_parents (root_idx, parents));
- find_subgraph (root_idx, subgraph);
- }
-
- unsigned original_root_idx = root_idx ();
- hb_hashmap_t<unsigned, unsigned> index_map;
- bool made_changes = false;
- for (auto entry : subgraph.iter ())
- {
- const auto& node = vertices_[entry.first];
- unsigned subgraph_incoming_edges = entry.second;
-
- if (subgraph_incoming_edges < node.incoming_edges ())
- {
- // Only de-dup objects with incoming links from outside the subgraph.
- made_changes = true;
- duplicate_subgraph (entry.first, index_map);
- }
- }
-
- if (!made_changes)
- return false;
-
- if (original_root_idx != root_idx ()
- && parents.has (original_root_idx))
- {
- // If the root idx has changed since parents was determined, update root idx in parents
- parents.add (root_idx ());
- parents.del (original_root_idx);
- }
-
- auto new_subgraph =
- + subgraph.keys ()
- | hb_map([&] (unsigned node_idx) {
- if (index_map.has (node_idx)) return index_map[node_idx];
- return node_idx;
- })
- ;
-
- remap_obj_indices (index_map, new_subgraph);
- remap_obj_indices (index_map, parents.iter (), true);
-
- // Update roots set with new indices as needed.
- unsigned next = HB_SET_VALUE_INVALID;
- while (roots.next (&next))
- {
- if (index_map.has (next))
- {
- roots.del (next);
- roots.add (index_map[next]);
- }
- }
-
- return true;
- }
-
- void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
- {
- for (const auto& link : vertices_[node_idx].obj.all_links ())
- {
- if (subgraph.has (link.objidx))
- {
- subgraph.set (link.objidx, subgraph[link.objidx] + 1);
- continue;
- }
- subgraph.set (link.objidx, 1);
- find_subgraph (link.objidx, subgraph);
- }
- }
-
- void find_subgraph (unsigned node_idx, hb_set_t& subgraph)
- {
- if (subgraph.has (node_idx)) return;
- subgraph.add (node_idx);
- for (const auto& link : vertices_[node_idx].obj.all_links ())
- find_subgraph (link.objidx, subgraph);
- }
-
- /*
- * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
- * links. index_map is updated with mappings from old id to new id. If a duplication has already
- * been performed for a given index, then it will be skipped.
- */
- void duplicate_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& index_map)
- {
- if (index_map.has (node_idx))
- return;
-
- index_map.set (node_idx, duplicate (node_idx));
- for (const auto& l : object (node_idx).all_links ()) {
- duplicate_subgraph (l.objidx, index_map);
- }
- }
-
- /*
- * Creates a copy of node_idx and returns it's new index.
- */
- unsigned duplicate (unsigned node_idx)
- {
- positions_invalid = true;
- distance_invalid = true;
-
- auto* clone = vertices_.push ();
- auto& child = vertices_[node_idx];
- if (vertices_.in_error ()) {
- return -1;
- }
-
- clone->obj.head = child.obj.head;
- clone->obj.tail = child.obj.tail;
- clone->distance = child.distance;
- clone->space = child.space;
- clone->parents.reset ();
-
- unsigned clone_idx = vertices_.length - 2;
- for (const auto& l : child.obj.real_links)
- {
- clone->obj.real_links.push (l);
- vertices_[l.objidx].parents.push (clone_idx);
- }
- for (const auto& l : child.obj.virtual_links)
- {
- clone->obj.virtual_links.push (l);
- vertices_[l.objidx].parents.push (clone_idx);
- }
-
- check_success (!clone->obj.real_links.in_error ());
- check_success (!clone->obj.virtual_links.in_error ());
-
- // 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;
-
- // Since the root moved, update the parents arrays of all children on the root.
- for (const auto& l : root.obj.all_links ())
- vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
-
- return clone_idx;
- }
-
- /*
- * Creates a copy of child and re-assigns the link from
- * parent to the clone. The copy is a shallow copy, objects
- * linked from child are not duplicated.
- */
- bool duplicate (unsigned parent_idx, unsigned child_idx)
- {
- update_parents ();
-
- unsigned links_to_child = 0;
- for (const auto& l : vertices_[parent_idx].obj.all_links ())
- {
- if (l.objidx == child_idx) links_to_child++;
- }
-
- if (vertices_[child_idx].incoming_edges () <= links_to_child)
- {
- // Can't duplicate this node, doing so would orphan the original one as all remaining links
- // to child are from parent.
- DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
- parent_idx, child_idx);
- return false;
- }
-
- DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
- parent_idx, child_idx);
-
- unsigned clone_idx = duplicate (child_idx);
- if (clone_idx == (unsigned) -1) return false;
- // duplicate shifts the root node idx, so if parent_idx was root update it.
- if (parent_idx == clone_idx) parent_idx++;
-
- auto& parent = vertices_[parent_idx];
- for (auto& l : parent.obj.all_links_writer ())
- {
- if (l.objidx != child_idx)
- continue;
-
- reassign_link (l, parent_idx, clone_idx);
- }
-
- return true;
- }
-
- /*
- * Raises the sorting priority of all children.
- */
- bool raise_childrens_priority (unsigned parent_idx)
- {
- DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d",
- parent_idx);
- // This operation doesn't change ordering until a sort is run, so no need
- // to invalidate positions. It does not change graph structure so no need
- // to update distances or edge counts.
- auto& parent = vertices_[parent_idx].obj;
- bool made_change = false;
- for (auto& l : parent.all_links_writer ())
- made_change |= vertices_[l.objidx].raise_priority ();
- return made_change;
- }
-
- /*
- * Will any offsets overflow on graph when it's serialized?
- */
- bool will_overflow (hb_vector_t<overflow_record_t>* overflows = nullptr)
- {
- if (overflows) overflows->resize (0);
- update_positions ();
-
- for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
- {
- // Don't need to check virtual links for overflow
- for (const auto& link : vertices_[parent_idx].obj.real_links)
- {
- int64_t offset = compute_offset (parent_idx, link);
- if (is_valid_offset (offset, link))
- continue;
-
- if (!overflows) return true;
-
- overflow_record_t r;
- r.parent = parent_idx;
- r.child = link.objidx;
- overflows->push (r);
- }
- }
-
- if (!overflows) return false;
- return overflows->length;
- }
-
- void print_orphaned_nodes ()
- {
- if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
-
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
- parents_invalid = true;
- update_parents();
-
- for (unsigned i = 0; i < root_idx (); i++)
- {
- const auto& v = vertices_[i];
- if (!v.parents)
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
- }
- }
-
- void print_overflows (const hb_vector_t<overflow_record_t>& overflows)
- {
- if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
-
- update_parents ();
- int limit = 10;
- for (const auto& o : overflows)
- {
- if (!limit--) break;
- const auto& parent = vertices_[o.parent];
- const auto& child = vertices_[o.child];
- DEBUG_MSG (SUBSET_REPACK, nullptr,
- " overflow from "
- "%4d (%4d in, %4d out, space %2d) => "
- "%4d (%4d in, %4d out, space %2d)",
- o.parent,
- parent.incoming_edges (),
- parent.obj.real_links.length + parent.obj.virtual_links.length,
- space_for (o.parent),
- o.child,
- child.incoming_edges (),
- child.obj.real_links.length + child.obj.virtual_links.length,
- space_for (o.child));
- }
- if (overflows.length > 10) {
- DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10);
- }
- }
-
- unsigned num_roots_for_space (unsigned space) const
- {
- return num_roots_for_space_[space];
- }
-
- unsigned next_space () const
- {
- return num_roots_for_space_.length;
- }
-
- void move_to_new_space (const hb_set_t& indices)
- {
- num_roots_for_space_.push (0);
- unsigned new_space = num_roots_for_space_.length - 1;
-
- for (unsigned index : indices) {
- auto& node = vertices_[index];
- num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
- num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
- node.space = new_space;
- distance_invalid = true;
- positions_invalid = true;
- }
- }
-
- unsigned space_for (unsigned index, unsigned* root = nullptr) const
- {
- const auto& node = vertices_[index];
- if (node.space)
- {
- if (root != nullptr)
- *root = index;
- return node.space;
- }
-
- if (!node.parents)
- {
- if (root)
- *root = index;
- return 0;
- }
-
- return space_for (node.parents[0], root);
- }
-
- void err_other_error () { this->successful = false; }
-
- private:
-
- size_t serialized_length () const {
- size_t total_size = 0;
- for (unsigned i = 0; i < vertices_.length; i++) {
- size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
- total_size += size;
- }
- return total_size;
- }
-
- /*
- * Returns the numbers of incoming edges that are 32bits wide.
- */
- unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
- {
- unsigned count = 0;
- hb_set_t visited;
- for (unsigned p : vertices_[node_idx].parents)
- {
- if (visited.has (p)) continue;
- visited.add (p);
-
- // Only real links can be wide
- for (const auto& l : vertices_[p].obj.real_links)
- {
- if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
- {
- count++;
- parents.add (p);
- }
- }
- }
- return count;
- }
-
- bool check_success (bool success)
- { return this->successful && (success || (err_other_error (), false)); }
-
- /*
- * Creates a map from objid to # of incoming edges.
- */
- void update_parents ()
- {
- if (!parents_invalid) return;
-
- for (unsigned i = 0; i < vertices_.length; i++)
- vertices_[i].parents.reset ();
-
- for (unsigned p = 0; p < vertices_.length; p++)
- {
- for (auto& l : vertices_[p].obj.all_links ())
- {
- vertices_[l.objidx].parents.push (p);
- }
- }
-
- parents_invalid = false;
- }
-
- /*
- * compute the serialized start and end positions for each vertex.
- */
- void update_positions ()
- {
- if (!positions_invalid) return;
-
- unsigned current_pos = 0;
- for (int i = root_idx (); i >= 0; i--)
- {
- auto& v = vertices_[i];
- v.start = current_pos;
- current_pos += v.obj.tail - v.obj.head;
- v.end = current_pos;
- }
-
- positions_invalid = false;
- }
-
- /*
- * Finds the distance to each object in the graph
- * from the initial node.
- */
- void update_distances ()
- {
- if (!distance_invalid) return;
-
- // Uses Dijkstra's algorithm to find all of the shortest distances.
- // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
- //
- // Implementation Note:
- // Since our priority queue doesn't support fast priority decreases
- // we instead just add new entries into the queue when a priority changes.
- // 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 fibonacci queue) with a fast decrease priority.
- for (unsigned i = 0; i < vertices_.length; i++)
- {
- if (i == vertices_.length - 1)
- vertices_[i].distance = 0;
- else
- vertices_[i].distance = hb_int_max (int64_t);
- }
-
- hb_priority_queue_t queue;
- queue.insert (0, vertices_.length - 1);
-
- hb_vector_t<bool> visited;
- visited.resize (vertices_.length);
-
- while (!queue.in_error () && !queue.is_empty ())
- {
- unsigned next_idx = queue.pop_minimum ().second;
- if (visited[next_idx]) continue;
- const auto& next = vertices_[next_idx];
- int64_t next_distance = vertices_[next_idx].distance;
- visited[next_idx] = true;
-
- for (const auto& link : next.obj.all_links ())
- {
- if (visited[link.objidx]) continue;
-
- const auto& child = vertices_[link.objidx].obj;
- unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
- int64_t child_weight = (child.tail - child.head) +
- ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
- int64_t child_distance = next_distance + child_weight;
-
- if (child_distance < vertices_[link.objidx].distance)
- {
- vertices_[link.objidx].distance = child_distance;
- queue.insert (child_distance, link.objidx);
- }
- }
- }
-
- check_success (!queue.in_error ());
- if (!check_success (queue.is_empty ()))
- {
- print_orphaned_nodes ();
- return;
- }
-
- distance_invalid = false;
- }
-
- int64_t compute_offset (
- unsigned parent_idx,
- const hb_serialize_context_t::object_t::link_t& link) const
- {
- const auto& parent = vertices_[parent_idx];
- const auto& child = vertices_[link.objidx];
- int64_t offset = 0;
- switch ((hb_serialize_context_t::whence_t) link.whence) {
- case hb_serialize_context_t::whence_t::Head:
- offset = child.start - parent.start; break;
- case hb_serialize_context_t::whence_t::Tail:
- offset = child.start - parent.end; break;
- case hb_serialize_context_t::whence_t::Absolute:
- offset = child.start; break;
- }
-
- assert (offset >= link.bias);
- offset -= link.bias;
- return offset;
- }
-
- bool is_valid_offset (int64_t offset,
- const hb_serialize_context_t::object_t::link_t& link) const
- {
- if (unlikely (!link.width))
- // Virtual links can't overflow.
- return link.is_signed || offset >= 0;
-
- if (link.is_signed)
- {
- if (link.width == 4)
- return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
- else
- return offset >= -(1 << 15) && offset < (1 << 15);
- }
- else
- {
- if (link.width == 4)
- return offset >= 0 && offset < ((int64_t) 1 << 32);
- else if (link.width == 3)
- return offset >= 0 && offset < ((int32_t) 1 << 24);
- else
- return offset >= 0 && offset < (1 << 16);
- }
- }
-
- /*
- * Updates a link in the graph to point to a different object. Corrects the
- * parents vector on the previous and new child nodes.
- */
- void reassign_link (hb_serialize_context_t::object_t::link_t& link,
- unsigned parent_idx,
- unsigned new_idx)
- {
- unsigned old_idx = link.objidx;
- link.objidx = new_idx;
- vertices_[old_idx].remove_parent (parent_idx);
- vertices_[new_idx].parents.push (parent_idx);
- }
-
- /*
- * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
- */
- template<typename Iterator, hb_requires (hb_is_iterator (Iterator))>
- void remap_obj_indices (const hb_hashmap_t<unsigned, unsigned>& id_map,
- Iterator subgraph,
- bool only_wide = false)
- {
- if (!id_map) return;
- for (unsigned i : subgraph)
- {
- for (auto& link : vertices_[i].obj.all_links_writer ())
- {
- if (!id_map.has (link.objidx)) continue;
- if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
-
- reassign_link (link, i, id_map[link.objidx]);
- }
- }
- }
-
- /*
- * Updates all objidx's in all links using the provided mapping.
- */
- void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
- hb_vector_t<vertex_t>* sorted_graph) const
- {
- for (unsigned i = 0; i < sorted_graph->length; i++)
- {
- (*sorted_graph)[i].remap_parents (id_map);
- for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
- {
- link.objidx = id_map[link.objidx];
- }
- }
- }
-
- template <typename O> void
- serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
- char* head,
- hb_serialize_context_t* c) const
- {
- OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
- *offset = 0;
- c->add_link (*offset,
- // serializer has an extra nil object at the start of the
- // object array. So all id's are +1 of what our id's are.
- link.objidx + 1,
- (hb_serialize_context_t::whence_t) link.whence,
- link.bias);
- }
-
- void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
- char* head,
- hb_serialize_context_t* c) const
- {
- switch (link.width)
- {
- case 0:
- // Virtual links aren't serialized.
- return;
- case 4:
- if (link.is_signed)
- {
- serialize_link_of_type<OT::HBINT32> (link, head, c);
- } else {
- serialize_link_of_type<OT::HBUINT32> (link, head, c);
- }
- return;
- case 2:
- if (link.is_signed)
- {
- serialize_link_of_type<OT::HBINT16> (link, head, c);
- } else {
- serialize_link_of_type<OT::HBUINT16> (link, head, c);
- }
- return;
- case 3:
- serialize_link_of_type<OT::HBUINT24> (link, head, c);
- return;
- default:
- // Unexpected link width.
- assert (0);
- }
- }
-
- /*
- * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
- * For this search the graph is treated as being undirected.
- *
- * Connected targets will be added to connected and removed from targets. All visited nodes
- * will be added to visited.
- */
- void find_connected_nodes (unsigned start_idx,
- hb_set_t& targets,
- 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);
-
- if (targets.has (start_idx))
- {
- targets.del (start_idx);
- connected.add (start_idx);
- }
-
- const auto& v = vertices_[start_idx];
-
- // Graph is treated as undirected so search children and parents of start_idx
- for (const auto& l : v.obj.all_links ())
- find_connected_nodes (l.objidx, targets, visited, connected);
-
- for (unsigned p : v.parents)
- find_connected_nodes (p, targets, visited, connected);
- }
-
- public:
- // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
- hb_vector_t<vertex_t> vertices_;
- private:
- bool parents_invalid;
- bool distance_invalid;
- bool positions_invalid;
- bool successful;
- hb_vector_t<unsigned> num_roots_for_space_;
-};
static inline
-bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
+bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
graph_t& sorted_graph)
{
unsigned space = 0;
@@ -1107,7 +51,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov
for (int i = overflows.length - 1; i >= 0; i--)
{
- const graph_t::overflow_record_t& r = overflows[i];
+ const graph::overflow_record_t& r = overflows[i];
unsigned root;
unsigned overflow_space = sorted_graph.space_for (r.parent, &root);
@@ -1149,7 +93,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov
}
static inline
-bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
+bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
hb_set_t& priority_bumped_parents,
graph_t& sorted_graph)
{
@@ -1158,7 +102,7 @@ bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflow
// Try resolving the furthest overflows first.
for (int i = overflows.length - 1; i >= 0; i--)
{
- const graph_t::overflow_record_t& r = overflows[i];
+ const graph::overflow_record_t& r = overflows[i];
const auto& child = sorted_graph.vertices_[r.child];
if (child.is_shared ())
{
@@ -1214,20 +158,18 @@ inline hb_blob_t*
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 ())
+ sorted_graph.sort_shortest_distance ();
+
+ bool will_overflow = graph::will_overflow (sorted_graph);
+ if (!will_overflow)
{
- return sorted_graph.serialize ();
+ return graph::serialize (sorted_graph);
}
- sorted_graph.sort_shortest_distance ();
-
if ((table_tag == HB_OT_TAG_GPOS
|| table_tag == HB_OT_TAG_GSUB)
- && sorted_graph.will_overflow ())
+ && will_overflow)
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
if (sorted_graph.assign_32bit_spaces ())
@@ -1235,13 +177,13 @@ hb_resolve_overflows (const T& packed,
}
unsigned round = 0;
- hb_vector_t<graph_t::overflow_record_t> overflows;
+ hb_vector_t<graph::overflow_record_t> overflows;
// TODO(garretrieger): select a good limit for max rounds.
while (!sorted_graph.in_error ()
- && sorted_graph.will_overflow (&overflows)
+ && graph::will_overflow (sorted_graph, &overflows)
&& round++ < max_rounds) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round);
- sorted_graph.print_overflows (overflows);
+ print_overflows (sorted_graph, overflows);
hb_set_t priority_bumped_parents;
@@ -1263,13 +205,13 @@ hb_resolve_overflows (const T& packed,
return nullptr;
}
- if (sorted_graph.will_overflow ())
+ if (graph::will_overflow (sorted_graph))
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
return nullptr;
}
- return sorted_graph.serialize ();
+ return graph::serialize (sorted_graph);
}
#endif /* HB_REPACKER_HH */
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index 40895a4548..cecdcdeb74 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -74,7 +74,7 @@ struct hb_serialize_context_t
}
object_t () = default;
-
+
#ifdef HB_EXPERIMENTAL_API
object_t (const hb_object_t &o)
{
@@ -91,6 +91,15 @@ struct hb_serialize_context_t
}
#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
@@ -111,10 +120,10 @@ 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;
@@ -686,7 +695,7 @@ struct hb_serialize_context_t
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
}
- public: /* TODO Make private. */
+ public:
char *start, *head, *tail, *end;
unsigned int debug_depth;
hb_serialize_error_t errors;
@@ -710,9 +719,7 @@ struct hb_serialize_context_t
hb_vector_t<object_t *> packed;
/* Map view of packed objects. */
- hb_hashmap_t<const object_t *, objidx_t,
- const object_t *, objidx_t,
- nullptr, 0> packed_map;
+ hb_hashmap_t<const object_t *, objidx_t> packed_map;
};
#endif /* HB_SERIALIZE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-set-digest.hh b/thirdparty/harfbuzz/src/hb-set-digest.hh
index 7d4979b73b..fab36216e4 100644
--- a/thirdparty/harfbuzz/src/hb-set-digest.hh
+++ b/thirdparty/harfbuzz/src/hb-set-digest.hh
@@ -30,7 +30,7 @@
#include "hb.hh"
/*
- * The set digests here implement various "filters" that support
+ * The set-digests here implement various "filters" that support
* "approximate member query". Conceptually these are like Bloom
* Filter and Quotient Filter, however, much smaller, faster, and
* designed to fit the requirements of our uses for glyph coverage
@@ -40,13 +40,25 @@
* set of glyphs, but fully flooded and ineffective if coverage is
* all over the place.
*
- * The frozen-set can be used instead of a digest, to trade more
- * memory for 100% accuracy, but in practice, that doesn't look like
- * an attractive trade-off.
+ * The way these are used is that the filter is first populated by
+ * a lookup's or subtable's Coverage table(s), and then when we
+ * want to apply the lookup or subtable to a glyph, before trying
+ * to apply, we ask the filter if the glyph may be covered. If it's
+ * not, we return early.
+ *
+ * We use these filters both at the lookup-level, and then again,
+ * at the subtable-level. Both have performance win.
+ *
+ * The main filter we use is a combination of three bits-pattern
+ * filters. A bits-pattern filter checks a number of bits (5 or 6)
+ * of the input number (glyph-id in this case) and checks whether
+ * its pattern is amongst the patterns of any of the accepted values.
+ * The accepted patterns are represented as a "long" integer. The
+ * check is done using four bitwise operations only.
*/
template <typename mask_t, unsigned int shift>
-struct hb_set_digest_lowest_bits_t
+struct hb_set_digest_bits_pattern_t
{
static constexpr unsigned mask_bytes = sizeof (mask_t);
static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
@@ -102,7 +114,7 @@ struct hb_set_digest_lowest_bits_t
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
bool may_have (hb_codepoint_t g) const
- { return !!(mask & mask_for (g)); }
+ { return mask & mask_for (g); }
private:
@@ -171,11 +183,11 @@ struct hb_set_digest_combiner_t
using hb_set_digest_t =
hb_set_digest_combiner_t
<
- hb_set_digest_lowest_bits_t<unsigned long, 4>,
+ hb_set_digest_bits_pattern_t<unsigned long, 4>,
hb_set_digest_combiner_t
<
- hb_set_digest_lowest_bits_t<unsigned long, 0>,
- hb_set_digest_lowest_bits_t<unsigned long, 9>
+ hb_set_digest_bits_pattern_t<unsigned long, 0>,
+ hb_set_digest_bits_pattern_t<unsigned long, 9>
>
>
;
diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc
index 0e2c1f77ef..2d458294f8 100644
--- a/thirdparty/harfbuzz/src/hb-set.cc
+++ b/thirdparty/harfbuzz/src/hb-set.cc
@@ -40,7 +40,7 @@
/**
- * hb_set_create: (Xconstructor)
+ * hb_set_create:
*
* Creates a new, initially empty set.
*
@@ -186,6 +186,7 @@ hb_set_t *
hb_set_copy (const hb_set_t *set)
{
hb_set_t *copy = hb_set_create ();
+ if (unlikely (!copy)) return nullptr;
copy->set (*set);
return copy;
}
@@ -359,6 +360,23 @@ hb_set_is_equal (const hb_set_t *set,
}
/**
+ * hb_set_hash:
+ * @set: A set
+ *
+ * Creates a hash representing @set.
+ *
+ * Return value:
+ * A hash of @set.
+ *
+ * Since: 4.4.0
+ **/
+HB_EXTERN unsigned int
+hb_set_hash (const hb_set_t *set)
+{
+ return set->hash ();
+}
+
+/**
* hb_set_is_subset:
* @set: A set
* @larger_set: Another set
diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h
index 10ce7c10d4..56902c267e 100644
--- a/thirdparty/harfbuzz/src/hb-set.h
+++ b/thirdparty/harfbuzz/src/hb-set.h
@@ -128,6 +128,9 @@ HB_EXTERN hb_bool_t
hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other);
+HB_EXTERN unsigned int
+hb_set_hash (const hb_set_t *set);
+
HB_EXTERN hb_bool_t
hb_set_is_subset (const hb_set_t *set,
const hb_set_t *larger_set);
diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh
index 1f05407869..7eb5e19a2a 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); }
@@ -125,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); }
@@ -158,15 +162,18 @@ 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 (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-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc
index 66332165c3..0af07825fc 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc
@@ -170,7 +170,7 @@ hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other)
/**
- * hb_shape_plan_create: (Xconstructor)
+ * hb_shape_plan_create:
* @face: #hb_face_t to use
* @props: The #hb_segment_properties_t of the segment
* @user_features: (array length=num_user_features): The list of user-selected features
@@ -198,7 +198,7 @@ hb_shape_plan_create (hb_face_t *face,
}
/**
- * hb_shape_plan_create2: (Xconstructor)
+ * hb_shape_plan_create2:
* @face: #hb_face_t to use
* @props: The #hb_segment_properties_t of the segment
* @user_features: (array length=num_user_features): The list of user-selected features
@@ -231,7 +231,8 @@ hb_shape_plan_create2 (hb_face_t *face,
num_coords,
shaper_list);
- assert (props->direction != HB_DIRECTION_INVALID);
+ if (unlikely (props->direction == HB_DIRECTION_INVALID))
+ return hb_shape_plan_get_empty ();
hb_shape_plan_t *shape_plan;
diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc
index 3407e1af42..14ec92828f 100644
--- a/thirdparty/harfbuzz/src/hb-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-shape.cc
@@ -50,7 +50,7 @@
static inline void free_static_shaper_list ();
-static const char *nil_shaper_list[] = {nullptr};
+static const char * const nil_shaper_list[] = {nullptr};
static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
hb_shaper_list_lazy_loader_t>
@@ -73,7 +73,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
}
static void destroy (const char **l)
{ hb_free (l); }
- static const char ** get_null ()
+ static const char * const * get_null ()
{ return nil_shaper_list; }
} static_shaper_list;
@@ -126,6 +126,11 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list)
{
+ if (unlikely (!buffer->len))
+ return true;
+
+ buffer->enter ();
+
hb_buffer_t *text_buffer = nullptr;
if (buffer->flags & HB_BUFFER_FLAG_VERIFY)
{
@@ -137,12 +142,19 @@ hb_shape_full (hb_font_t *font,
features, num_features,
font->coords, font->num_coords,
shaper_list);
+
hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+
+ if (buffer->max_ops <= 0)
+ buffer->shaping_failed = true;
+
hb_shape_plan_destroy (shape_plan);
if (text_buffer)
{
- if (res && !buffer->verify (text_buffer,
+ if (res && buffer->successful && !buffer->shaping_failed
+ && text_buffer->successful
+ && !buffer->verify (text_buffer,
font,
features,
num_features,
@@ -151,6 +163,8 @@ hb_shape_full (hb_font_t *font,
hb_buffer_destroy (text_buffer);
}
+ buffer->leave ();
+
return res;
}
diff --git a/thirdparty/harfbuzz/src/hb-shaper.cc b/thirdparty/harfbuzz/src/hb-shaper.cc
index a11ed83afd..da4253ed64 100644
--- a/thirdparty/harfbuzz/src/hb-shaper.cc
+++ b/thirdparty/harfbuzz/src/hb-shaper.cc
@@ -29,18 +29,18 @@
#include "hb-machinery.hh"
-static const hb_shaper_entry_t all_shapers[] = {
+static const hb_shaper_entry_t _hb_all_shapers[] = {
#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
};
#ifndef HB_NO_SHAPER
-static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled.");
+static_assert (0 != ARRAY_LENGTH_CONST (_hb_all_shapers), "No shaper enabled.");
#endif
static inline void free_static_shapers ();
-static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_t,
+static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<hb_shaper_entry_t,
hb_shapers_lazy_loader_t>
{
static hb_shaper_entry_t *create ()
@@ -49,11 +49,11 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
if (!env || !*env)
return nullptr;
- hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (all_shapers));
+ hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (_hb_all_shapers));
if (unlikely (!shapers))
return nullptr;
- memcpy (shapers, all_shapers, sizeof (all_shapers));
+ memcpy (shapers, _hb_all_shapers, sizeof (_hb_all_shapers));
/* Reorder shaper list to prefer requested shapers. */
unsigned int i = 0;
@@ -64,7 +64,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
if (!end)
end = p + strlen (p);
- for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+ for (unsigned int j = i; j < ARRAY_LENGTH (_hb_all_shapers); j++)
if (end - p == (int) strlen (shapers[j].name) &&
0 == strncmp (shapers[j].name, p, end - p))
{
@@ -85,8 +85,8 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
return shapers;
}
- static void destroy (const hb_shaper_entry_t *p) { hb_free ((void *) p); }
- static const hb_shaper_entry_t *get_null () { return all_shapers; }
+ static void destroy (hb_shaper_entry_t *p) { hb_free (p); }
+ static const hb_shaper_entry_t *get_null () { return _hb_all_shapers; }
} static_shapers;
static inline
diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc
index 7cc51be611..5c5ecce880 100644
--- a/thirdparty/harfbuzz/src/hb-static.cc
+++ b/thirdparty/harfbuzz/src/hb-static.cc
@@ -53,6 +53,9 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF};
const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
+/* hb_map_t */
+
+const hb_codepoint_t minus_1 = -1;
/* hb_face_t */
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
index 18657705fa..bb9f27eec1 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
@@ -40,11 +40,12 @@ 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)
{
- if (unlikely (buff.push (b) == &Crap (unsigned char)))
+ buff.push (b);
+ if (unlikely (buff.in_error ()))
set_error ();
}
@@ -107,20 +108,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 +252,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)
@@ -317,9 +316,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>
@@ -398,19 +397,19 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
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)
{
@@ -468,6 +467,7 @@ struct subr_remap_t : hb_inc_bimap_t
* 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);
@@ -561,19 +561,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;
@@ -593,11 +595,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))
@@ -618,11 +621,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);
}
}
@@ -849,9 +853,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 ())
@@ -860,7 +865,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 35fecd67bc..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;
}
@@ -442,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++)
{
@@ -451,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);
@@ -464,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);
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc
index 92dd6b1d2c..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 ())
@@ -245,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;
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc
index 4885280996..028ddf9035 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-input.cc
@@ -140,7 +140,20 @@ hb_subset_input_create_or_fail (void)
HB_TAG ('r', 't', 'l', 'a'),
HB_TAG ('r', 't', 'l', 'm'),
- //Complex shapers
+ //random
+ HB_TAG ('r', 'a', 'n', 'd'),
+
+ //justify
+ HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might
+
+ //private
+ HB_TAG ('H', 'a', 'r', 'f'),
+ HB_TAG ('H', 'A', 'R', 'F'),
+ HB_TAG ('B', 'u', 'z', 'z'),
+ HB_TAG ('B', 'U', 'Z', 'Z'),
+
+ //shapers
+
//arabic
HB_TAG ('i', 'n', 'i', 't'),
HB_TAG ('m', 'e', 'd', 'i'),
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 74b7e3977c..4e3bb1d477 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -41,9 +41,9 @@
#include "hb-ot-math-table.hh"
using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
-
-typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map;
+typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
static inline void
_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
@@ -204,7 +204,7 @@ static inline void
hb_map_t *layout_variation_idx_map)
{
hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face);
- hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
+ hb_blob_ptr_t<GPOS> gpos = hb_sanitize_context_t ().reference_table<GPOS> (face);
if (!gdef->has_data ())
{
@@ -279,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,12 +289,13 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
{
OT::cmap::accelerator_t cmap (plan->source);
- constexpr static const int size_threshold = 4096;
-
+ 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;
@@ -310,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;
@@ -338,8 +339,41 @@ _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);
+ 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));
+ }
+}
+
+#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
+#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64
+#endif
+
+static unsigned
+_glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
+ hb_codepoint_t gid,
+ hb_set_t *gids_to_retain,
+ int operation_count,
+ unsigned depth = 0)
+{
+ if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
+ if (unlikely (--operation_count < 0)) return operation_count;
+ /* Check if is already visited */
+ if (gids_to_retain->has (gid)) return operation_count;
+
+ gids_to_retain->add (gid);
+
+ for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
+ operation_count =
+ _glyf_add_gid_and_children (glyf,
+ item.glyphIndex,
+ gids_to_retain,
+ operation_count,
+ depth);
+
+ return operation_count;
}
static void
@@ -348,7 +382,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
bool close_over_gpos,
bool close_over_gdef)
{
- OT::glyf::accelerator_t glyf (plan->source);
+ OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF
OT::cff1::accelerator_t cff (plan->source);
#endif
@@ -369,7 +403,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
plan->gsub_langsys);
if (close_over_gpos)
- _closure_glyphs_lookups_features<OT::GPOS> (
+ _closure_glyphs_lookups_features<GPOS> (
plan->source,
plan->_glyphset_gsub,
plan->layout_features,
@@ -388,16 +422,20 @@ _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 (glyf, gid, plan->_glyphset,
+ cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH);
+ 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 ());
@@ -413,6 +451,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
}
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
_create_old_gid_to_new_gid_map (const hb_face_t *face,
bool retain_gids,
const hb_set_t *all_gids_to_retain,
@@ -420,13 +472,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> (_, _);
@@ -434,10 +492,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;
}
@@ -485,6 +542,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
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);
@@ -502,6 +562,7 @@ hb_subset_plan_create_or_fail (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 ();
@@ -536,6 +597,19 @@ hb_subset_plan_create_or_fail (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;
@@ -558,6 +632,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);
@@ -569,6 +644,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);
@@ -584,9 +660,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
if (plan->gsub_langsys)
{
- for (auto _ : plan->gsub_langsys->iter ())
- hb_set_destroy (_.second);
-
hb_object_destroy (plan->gsub_langsys);
plan->gsub_langsys->fini_shallow ();
hb_free (plan->gsub_langsys);
@@ -594,9 +667,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
if (plan->gpos_langsys)
{
- for (auto _ : plan->gpos_langsys->iter ())
- hb_set_destroy (_.second);
-
hb_object_destroy (plan->gpos_langsys);
plan->gpos_langsys->fini_shallow ();
hb_free (plan->gpos_langsys);
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index ab2c4c302c..2aaf19c61d 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;
@@ -85,8 +87,8 @@ struct hb_subset_plan_t
hb_map_t *gpos_lookups;
//active langsys we'd like to retain
- hb_hashmap_t<unsigned, hb_set_t *> *gsub_langsys;
- hb_hashmap_t<unsigned, hb_set_t *> *gpos_langsys;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gsub_langsys;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gpos_langsys;
//active features after removing redundant langsys and prune_features
hb_map_t *gsub_features;
diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc
index 4588268b76..10c572c2f7 100644
--- a/thirdparty/harfbuzz/src/hb-subset.cc
+++ b/thirdparty/harfbuzz/src/hb-subset.cc
@@ -56,6 +56,7 @@
#include "hb-repacker.hh"
using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
/**
* SECTION:hb-subset
@@ -78,13 +79,117 @@ using OT::Layout::GSUB::GSUB;
* retain glyph ids option and configure the subset to pass through the layout tables untouched.
*/
+/*
+ * The list of tables in the open type spec. Used to check for tables that may need handling
+ * if we are unable to list the tables in a face.
+ */
+static hb_tag_t known_tables[] {
+ HB_TAG ('a', 'v', 'a', 'r'),
+ HB_OT_TAG_BASE,
+ HB_OT_TAG_CBDT,
+ HB_OT_TAG_CBLC,
+ HB_OT_TAG_cff1,
+ HB_OT_TAG_cff2,
+ HB_OT_TAG_cmap,
+ HB_OT_TAG_COLR,
+ HB_OT_TAG_CPAL,
+ HB_TAG ('c', 'v', 'a', 'r'),
+ HB_TAG ('c', 'v', 't', ' '),
+ HB_TAG ('D', 'S', 'I', 'G'),
+ HB_TAG ('E', 'B', 'D', 'T'),
+ HB_TAG ('E', 'B', 'L', 'C'),
+ HB_TAG ('E', 'B', 'S', 'C'),
+ HB_TAG ('f', 'p', 'g', 'm'),
+ HB_TAG ('f', 'v', 'a', 'r'),
+ HB_TAG ('g', 'a', 's', 'p'),
+ HB_OT_TAG_GDEF,
+ HB_OT_TAG_glyf,
+ HB_OT_TAG_GPOS,
+ HB_OT_TAG_GSUB,
+ HB_OT_TAG_gvar,
+ HB_OT_TAG_hdmx,
+ HB_OT_TAG_head,
+ HB_OT_TAG_hhea,
+ HB_OT_TAG_hmtx,
+ HB_OT_TAG_HVAR,
+ HB_OT_TAG_JSTF,
+ HB_TAG ('k', 'e', 'r', 'n'),
+ HB_OT_TAG_loca,
+ HB_TAG ('L', 'T', 'S', 'H'),
+ HB_OT_TAG_MATH,
+ HB_OT_TAG_maxp,
+ HB_TAG ('M', 'E', 'R', 'G'),
+ HB_TAG ('m', 'e', 't', 'a'),
+ HB_TAG ('M', 'V', 'A', 'R'),
+ HB_TAG ('P', 'C', 'L', 'T'),
+ HB_OT_TAG_post,
+ HB_TAG ('p', 'r', 'e', 'p'),
+ HB_OT_TAG_sbix,
+ HB_TAG ('S', 'T', 'A', 'T'),
+ HB_TAG ('S', 'V', 'G', ' '),
+ HB_TAG ('V', 'D', 'M', 'X'),
+ HB_OT_TAG_vhea,
+ HB_OT_TAG_vmtx,
+ HB_OT_TAG_VORG,
+ HB_OT_TAG_VVAR,
+ HB_OT_TAG_name,
+ HB_OT_TAG_OS2
+};
+
+static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag)
+{
+ hb_blob_t* blob = hb_face_reference_table (face, tag);
+ bool result = (blob == hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+ return result;
+}
+
+static unsigned int
+_get_table_tags (const hb_subset_plan_t* plan,
+ unsigned int start_offset,
+ unsigned int *table_count, /* IN/OUT */
+ hb_tag_t *table_tags /* OUT */)
+{
+ unsigned num_tables = hb_face_get_table_tags (plan->source, 0, nullptr, nullptr);
+ if (num_tables)
+ return hb_face_get_table_tags (plan->source, start_offset, table_count, table_tags);
+
+ // If face has 0 tables associated with it, assume that it was built from
+ // hb_face_create_tables and thus is unable to list its tables. Fallback to
+ // checking each table type we can handle for existence instead.
+ auto it =
+ hb_concat (
+ + hb_array (known_tables)
+ | hb_filter ([&] (hb_tag_t tag) {
+ return !_table_is_empty (plan->source, tag) && !plan->no_subset_tables->has (tag);
+ })
+ | hb_map ([] (hb_tag_t tag) -> hb_tag_t { return tag; }),
+
+ plan->no_subset_tables->iter ()
+ | hb_filter([&] (hb_tag_t tag) {
+ return !_table_is_empty (plan->source, tag);
+ }));
+
+ it += start_offset;
+
+ unsigned num_written = 0;
+ while (bool (it) && num_written < *table_count)
+ table_tags[num_written++] = *it++;
+
+ *table_count = num_written;
+ return num_written;
+}
+
+
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));
@@ -123,7 +228,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> ();
@@ -136,7 +240,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);
@@ -147,13 +252,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> ();
@@ -167,10 +272,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)))
@@ -181,10 +289,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);
@@ -219,9 +327,17 @@ _subset (hb_subset_plan_t *plan)
static bool
_is_table_present (hb_face_t *source, hb_tag_t tag)
{
+
+ if (!hb_face_get_table_tags (source, 0, nullptr, nullptr)) {
+ // If face has 0 tables associated with it, assume that it was built from
+ // hb_face_create_tables and thus is unable to list its tables. Fallback to
+ // checking if the blob associated with tag is empty.
+ return !_table_is_empty (source, tag);
+ }
+
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))
+ while (((void) hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
{
for (unsigned i = 0; i < num_tables; ++i)
if (table_tags[i] == tag)
@@ -274,7 +390,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);
@@ -283,42 +401,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 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 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:
@@ -379,19 +497,22 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
bool success = true;
hb_tag_t table_tags[32];
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
- while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables))
+ hb_vector_t<char> buf;
+ buf.alloc (4096 - 16);
+
+ while (((void) _get_table_tags (plan, 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:
+end:
return success ? hb_face_reference (plan->dest) : nullptr;
}
diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh
index 1a4c89c17f..9e76ca460b 100644
--- a/thirdparty/harfbuzz/src/hb-ucd-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh
@@ -13,7 +13,7 @@
#include "hb.hh"
static const hb_script_t
-_hb_ucd_sc_map[162] =
+_hb_ucd_sc_map[163] =
{
HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED,
HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC,
@@ -96,6 +96,7 @@ _hb_ucd_sc_map[162] =
HB_SCRIPT_YEZIDI, HB_SCRIPT_CYPRO_MINOAN,
HB_SCRIPT_OLD_UYGHUR, HB_SCRIPT_TANGSA,
HB_SCRIPT_TOTO, HB_SCRIPT_VITHKUQI,
+ HB_SCRIPT_MATH,
};
static const uint16_t
_hb_ucd_dm1_p0_map[825] =
diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc
index 83ead6398b..05f74b9237 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.cc
+++ b/thirdparty/harfbuzz/src/hb-unicode.cc
@@ -169,7 +169,7 @@ hb_unicode_funcs_get_default ()
#endif
/**
- * hb_unicode_funcs_create: (Xconstructor)
+ * hb_unicode_funcs_create:
* @parent: (nullable): Parent Unicode-functions structure
*
* Creates a new #hb_unicode_funcs_t structure of Unicode functions.
diff --git a/thirdparty/harfbuzz/src/hb-unicode.hh b/thirdparty/harfbuzz/src/hb-unicode.hh
index 4c28bb0cdf..39aaee5baa 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.hh
+++ b/thirdparty/harfbuzz/src/hb-unicode.hh
@@ -105,12 +105,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
unsigned int
modified_combining_class (hb_codepoint_t u)
{
- /* XXX This hack belongs to the USE shaper (for Tai Tham):
- * Reorder SAKOT to ensure it comes after any tone marks. */
+ /* Reorder SAKOT to ensure it comes after any tone marks. */
if (unlikely (u == 0x1A60u)) return 254;
-
- /* XXX This hack belongs to the Tibetan shaper:
- * Reorder PADMA to ensure it comes after any vowel marks. */
+ /* Reorder PADMA to ensure it comes after any vowel marks. */
if (unlikely (u == 0x0FC6u)) return 254;
/* Reorder TSA -PHRU to reorder before U+0F74 */
if (unlikely (u == 0x0F39u)) return 127;
diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh
index 6c7d32e49d..7b08e3b4d2 100644
--- a/thirdparty/harfbuzz/src/hb-vector.hh
+++ b/thirdparty/harfbuzz/src/hb-vector.hh
@@ -29,6 +29,7 @@
#include "hb.hh"
#include "hb-array.hh"
+#include "hb-meta.hh"
#include "hb-null.hh"
@@ -42,6 +43,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
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 ());
@@ -59,7 +61,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
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)
{
@@ -70,9 +73,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
~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;
@@ -108,7 +110,10 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
{
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)
@@ -184,12 +189,14 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
{
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)
{
- /* TODO Emplace? */
Type *p = push ();
if (p == &Crap (Type))
// If push failed to allocate then don't copy v, since this may cause
@@ -199,18 +206,34 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
*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 (std::is_trivially_copy_assignable<T>::value)>
+ 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 (!std::is_trivially_copy_assignable<T>::value)>
+ hb_enable_if (!hb_is_trivially_copy_assignable(T))>
Type *
realloc_vector (unsigned new_allocated)
{
@@ -230,8 +253,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_constructible<T>::value ||
- !std::is_default_constructible<T>::value)>
+ hb_enable_if (hb_is_trivially_constructible(T))>
void
grow_vector (unsigned size)
{
@@ -239,8 +261,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
length = size;
}
template <typename T = Type,
- hb_enable_if (!std::is_trivially_constructible<T>::value &&
- std::is_default_constructible<T>::value)>
+ hb_enable_if (!hb_is_trivially_constructible(T))>
void
grow_vector (unsigned size)
{
@@ -252,14 +273,52 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_destructible<T>::value)>
+ 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 (!std::is_trivially_destructible<T>::value)>
+ hb_enable_if (!hb_is_trivially_destructible(T))>
void
shrink_vector (unsigned size)
{
@@ -271,7 +330,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
}
template <typename T = Type,
- hb_enable_if (std::is_trivially_copy_assignable<T>::value)>
+ hb_enable_if (hb_is_trivially_copy_assignable(T))>
void
shift_down_vector (unsigned i)
{
@@ -280,7 +339,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
(length - i) * sizeof (Type));
}
template <typename T = Type,
- hb_enable_if (!std::is_trivially_copy_assignable<T>::value)>
+ hb_enable_if (!hb_is_trivially_copy_assignable(T))>
void
shift_down_vector (unsigned i)
{
@@ -341,7 +400,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
Type pop ()
{
if (!length) return Null (Type);
- Type v = std::move (arrayZ[length - 1]);
+ Type v = arrayZ[length - 1];
arrayZ[length - 1].~Type ();
length--;
return v;
@@ -351,8 +410,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
{
if (unlikely (i >= length))
return;
- arrayZ[i].~Type ();
shift_down_vector (i + 1);
+ arrayZ[length - 1].~Type ();
length--;
}
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index 39fbde45c1..f036a12226 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -47,20 +47,20 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 2
+#define HB_VERSION_MINOR 4
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 1
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "4.2.0"
+#define HB_VERSION_STRING "4.4.1"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh
index b9f5f71415..8ec638a2b4 100644
--- a/thirdparty/harfbuzz/src/hb.hh
+++ b/thirdparty/harfbuzz/src/hb.hh
@@ -29,7 +29,6 @@
#ifndef HB_HH
#define HB_HH
-
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
#ifdef _MSC_VER
#pragma warning( disable: 4068 ) /* Unknown pragma */
@@ -65,6 +64,7 @@
#pragma GCC diagnostic error "-Wbitwise-instead-of-logical"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
+#pragma GCC diagnostic error "-Wcomma"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
#pragma GCC diagnostic error "-Wembedded-directive"
#pragma GCC diagnostic error "-Wextra-semi-stmt"
@@ -183,7 +183,7 @@
#include <cassert>
#include <cfloat>
#include <climits>
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
# define _USE_MATH_DEFINES
#endif
#include <cmath>
@@ -470,6 +470,7 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
* them directly.*/
+#include "hb-cplusplus.hh"
#include "hb-meta.hh"
#include "hb-mutex.hh"
#include "hb-number.hh"