aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:01:25 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:01:25 +0000
commit06242a1c93f937d95671d12f3c80a5c1507801dd (patch)
tree02a040078ef498ed6794d92f9d6eb17c33d074f3
parent68d5dd33a57b50b31c825665f4b70d78fe38ab02 (diff)
parenta17ca3ffec0711b9e5e0b991071b8f76bc295b95 (diff)
downloadharfbuzz_ng-aml_sta_341615000.tar.gz
Change-Id: I9c747428462b072f99fb990a3fd7e01eec899f83
-rwxr-xr-x.ci/build-win32.sh4
-rw-r--r--.ci/build-win64.sh4
-rwxr-xr-x.ci/deploy-docs.sh6
-rw-r--r--.circleci/config.yml56
-rw-r--r--.github/dependabot.yml6
-rw-r--r--.github/workflows/arm-ci.yml25
-rw-r--r--.github/workflows/cifuzz.yml2
-rw-r--r--.github/workflows/configs-build.yml27
-rw-r--r--.github/workflows/coverity-scan.yml11
-rw-r--r--.github/workflows/linux-ci.yml16
-rw-r--r--.github/workflows/macos-ci.yml19
-rw-r--r--.github/workflows/msvc-ci.yml19
-rw-r--r--.github/workflows/msys2-ci.yml11
-rw-r--r--Android.bp274
-rw-r--r--BUILD.md28
-rw-r--r--CMakeLists.txt89
-rw-r--r--CONFIG.md22
-rw-r--r--LICENSE4735
-rw-r--r--LICENSE_APACHE2.TXT202
-rw-r--r--LICENSE_FSFAP.TXT4
-rw-r--r--LICENSE_GPLv2.TXT125
-rw-r--r--LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT307
-rw-r--r--LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT663
-rw-r--r--LICENSE_HPND_SELL_VARIANT.TXT17
-rw-r--r--LICENSE_ISC.TXT11
-rw-r--r--LICENSE_MIT_MODERN_VARIANT.TXT15
-rw-r--r--LICENSE_OFL.TXT85
-rw-r--r--METADATA31
-rw-r--r--Makefile.am16
-rw-r--r--NEWS487
-rw-r--r--OWNERS1
l---------[-rw-r--r--]README16
-rw-r--r--README.md80
-rw-r--r--README.mingw.md11
-rw-r--r--README.version3
-rw-r--r--RELEASING.md2
-rw-r--r--TESTING.md12
-rw-r--r--TODO28
-rw-r--r--configure.ac20
-rw-r--r--docs/Makefile.am2
-rw-r--r--docs/features.dot259
-rw-r--r--docs/harfbuzz-docs.xml12
-rw-r--r--docs/harfbuzz-sections.txt472
-rw-r--r--docs/meson.build4
-rw-r--r--docs/repacker.md109
-rw-r--r--docs/serializer.md178
-rw-r--r--docs/subset-preprocessing.md228
-rw-r--r--docs/usermanual-clusters.xml2
-rw-r--r--docs/usermanual-getting-started.xml2
-rw-r--r--docs/usermanual-integration.xml4
-rw-r--r--docs/usermanual-object-model.xml50
-rw-r--r--docs/usermanual-opentype-features.xml6
-rw-r--r--docs/usermanual-shaping-concepts.xml47
-rw-r--r--docs/usermanual-what-is-harfbuzz.xml3
-rw-r--r--generate_notice.py732
-rw-r--r--git.mk7
-rw-r--r--harfbuzz.doap8
-rw-r--r--meson.build159
-rwxr-xr-xmingw-configure.sh4
-rw-r--r--perf/Makefile.am23
-rw-r--r--perf/README.md54
-rw-r--r--perf/benchmark-font.cc245
-rw-r--r--perf/benchmark-map.cc68
-rw-r--r--perf/benchmark-ot.cc44
-rw-r--r--perf/benchmark-set.cc151
-rw-r--r--perf/benchmark-shape.cc180
-rw-r--r--perf/benchmark-subset.cc259
-rw-r--r--perf/meson.build67
-rw-r--r--perf/perf-draw.hh177
-rw-r--r--perf/perf-extents.hh98
-rw-r--r--perf/perf-shaping.hh65
-rw-r--r--perf/perf.cc16
-rwxr-xr-xperf/run.sh25
-rw-r--r--perf/texts/fa-monologue.txt1
-rw-r--r--perf/texts/fa-words.txt10000
-rw-r--r--perf/texts/hi-words.txt10000
-rw-r--r--src/ArabicPUASimplified.txt250
-rw-r--r--src/ArabicPUATraditional.txt295
-rw-r--r--src/Makefile.am112
-rw-r--r--src/Makefile.sources151
-rw-r--r--src/OT/Layout/Common/Coverage.hh336
-rw-r--r--src/OT/Layout/Common/CoverageFormat1.hh133
-rw-r--r--src/OT/Layout/Common/CoverageFormat2.hh232
-rw-r--r--src/OT/Layout/Common/RangeRecord.hh85
-rw-r--r--src/OT/Layout/GPOS/Anchor.hh83
-rw-r--r--src/OT/Layout/GPOS/AnchorFormat1.hh46
-rw-r--r--src/OT/Layout/GPOS/AnchorFormat2.hh58
-rw-r--r--src/OT/Layout/GPOS/AnchorFormat3.hh100
-rw-r--r--src/OT/Layout/GPOS/AnchorMatrix.hh77
-rw-r--r--src/OT/Layout/GPOS/ChainContextPos.hh14
-rw-r--r--src/OT/Layout/GPOS/Common.hh33
-rw-r--r--src/OT/Layout/GPOS/ContextPos.hh14
-rw-r--r--src/OT/Layout/GPOS/CursivePos.hh35
-rw-r--r--src/OT/Layout/GPOS/CursivePosFormat1.hh301
-rw-r--r--src/OT/Layout/GPOS/ExtensionPos.hh17
-rw-r--r--src/OT/Layout/GPOS/GPOS.hh171
-rw-r--r--src/OT/Layout/GPOS/LigatureArray.hh56
-rw-r--r--src/OT/Layout/GPOS/MarkArray.hh128
-rw-r--r--src/OT/Layout/GPOS/MarkBasePos.hh41
-rw-r--r--src/OT/Layout/GPOS/MarkBasePosFormat1.hh219
-rw-r--r--src/OT/Layout/GPOS/MarkLigPos.hh41
-rw-r--r--src/OT/Layout/GPOS/MarkLigPosFormat1.hh206
-rw-r--r--src/OT/Layout/GPOS/MarkMarkPos.hh42
-rw-r--r--src/OT/Layout/GPOS/MarkMarkPosFormat1.hh228
-rw-r--r--src/OT/Layout/GPOS/MarkRecord.hh52
-rw-r--r--src/OT/Layout/GPOS/PairPos.hh46
-rw-r--r--src/OT/Layout/GPOS/PairPosFormat1.hh219
-rw-r--r--src/OT/Layout/GPOS/PairPosFormat2.hh351
-rw-r--r--src/OT/Layout/GPOS/PairSet.hh203
-rw-r--r--src/OT/Layout/GPOS/PairValueRecord.hh99
-rw-r--r--src/OT/Layout/GPOS/PosLookup.hh79
-rw-r--r--src/OT/Layout/GPOS/PosLookupSubTable.hh79
-rw-r--r--src/OT/Layout/GPOS/SinglePos.hh100
-rw-r--r--src/OT/Layout/GPOS/SinglePosFormat1.hh156
-rw-r--r--src/OT/Layout/GPOS/SinglePosFormat2.hh176
-rw-r--r--src/OT/Layout/GPOS/ValueFormat.hh394
-rw-r--r--src/OT/Layout/GSUB/AlternateSet.hh126
-rw-r--r--src/OT/Layout/GSUB/AlternateSubst.hh62
-rw-r--r--src/OT/Layout/GSUB/AlternateSubstFormat1.hh128
-rw-r--r--src/OT/Layout/GSUB/ChainContextSubst.hh18
-rw-r--r--src/OT/Layout/GSUB/Common.hh21
-rw-r--r--src/OT/Layout/GSUB/ContextSubst.hh18
-rw-r--r--src/OT/Layout/GSUB/ExtensionSubst.hh22
-rw-r--r--src/OT/Layout/GSUB/GSUB.hh61
-rw-r--r--src/OT/Layout/GSUB/Ligature.hh187
-rw-r--r--src/OT/Layout/GSUB/LigatureSet.hh119
-rw-r--r--src/OT/Layout/GSUB/LigatureSubst.hh71
-rw-r--r--src/OT/Layout/GSUB/LigatureSubstFormat1.hh166
-rw-r--r--src/OT/Layout/GSUB/MultipleSubst.hh62
-rw-r--r--src/OT/Layout/GSUB/MultipleSubstFormat1.hh130
-rw-r--r--src/OT/Layout/GSUB/ReverseChainSingleSubst.hh36
-rw-r--r--src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh244
-rw-r--r--src/OT/Layout/GSUB/Sequence.hh165
-rw-r--r--src/OT/Layout/GSUB/SingleSubst.hh103
-rw-r--r--src/OT/Layout/GSUB/SingleSubstFormat1.hh168
-rw-r--r--src/OT/Layout/GSUB/SingleSubstFormat2.hh151
-rw-r--r--src/OT/Layout/GSUB/SubstLookup.hh220
-rw-r--r--src/OT/Layout/GSUB/SubstLookupSubTable.hh77
-rw-r--r--src/OT/Layout/types.hh66
-rw-r--r--src/OT/glyf/CompositeGlyph.hh369
-rw-r--r--src/OT/glyf/Glyph.hh463
-rw-r--r--src/OT/glyf/GlyphHeader.hh50
-rw-r--r--src/OT/glyf/SimpleGlyph.hh339
-rw-r--r--src/OT/glyf/SubsetGlyph.hh93
-rw-r--r--src/OT/glyf/VarCompositeGlyph.hh353
-rw-r--r--src/OT/glyf/composite-iter.hh68
-rw-r--r--src/OT/glyf/coord-setter.hh34
-rw-r--r--src/OT/glyf/glyf-helpers.hh90
-rw-r--r--src/OT/glyf/glyf.hh448
-rw-r--r--src/OT/glyf/loca.hh43
-rw-r--r--src/OT/glyf/path-builder.hh135
-rwxr-xr-xsrc/check-c-linkage-decls.py18
-rwxr-xr-xsrc/check-header-guards.py22
-rwxr-xr-xsrc/check-includes.py20
-rwxr-xr-xsrc/check-static-inits.py2
-rwxr-xr-xsrc/check-symbols.py10
-rw-r--r--src/failing-alloc.c8
-rwxr-xr-x[-rw-r--r--]src/fix_get_types.py0
-rwxr-xr-xsrc/gen-arabic-joining-list.py6
-rwxr-xr-xsrc/gen-arabic-pua.py35
-rwxr-xr-xsrc/gen-arabic-table.py135
-rwxr-xr-xsrc/gen-def.py21
-rwxr-xr-xsrc/gen-emoji-table.py10
-rwxr-xr-xsrc/gen-harfbuzzcc.py14
-rwxr-xr-xsrc/gen-hb-version.py8
-rwxr-xr-xsrc/gen-indic-table.py505
-rwxr-xr-xsrc/gen-os2-unicode-ranges.py2
-rwxr-xr-xsrc/gen-tag-table.py210
-rwxr-xr-xsrc/gen-ucd-table.py57
-rwxr-xr-xsrc/gen-use-table.py204
-rwxr-xr-xsrc/gen-vowel-constraints.py8
-rw-r--r--src/graph/classdef-graph.hh216
-rw-r--r--src/graph/coverage-graph.hh152
-rw-r--r--src/graph/graph.hh1385
-rw-r--r--src/graph/gsubgpos-context.cc70
-rw-r--r--src/graph/gsubgpos-context.hh61
-rw-r--r--src/graph/gsubgpos-graph.hh414
-rw-r--r--src/graph/markbasepos-graph.hh510
-rw-r--r--src/graph/pairpos-graph.hh647
-rw-r--r--src/graph/serialize.hh270
-rw-r--r--src/graph/split-helpers.hh69
-rw-r--r--src/graph/test-classdef-graph.cc119
-rw-r--r--src/harfbuzz-config.cmake.in44
-rw-r--r--src/harfbuzz-subset.cc57
-rw-r--r--src/harfbuzz-subset.pc.in4
-rw-r--r--src/harfbuzz.cc38
-rw-r--r--src/hb-aat-layout-bsln-table.hh4
-rw-r--r--src/hb-aat-layout-common.hh22
-rw-r--r--src/hb-aat-layout-feat-table.hh2
-rw-r--r--src/hb-aat-layout-just-table.hh32
-rw-r--r--src/hb-aat-layout-kerx-table.hh10
-rw-r--r--src/hb-aat-layout-morx-table.hh19
-rw-r--r--src/hb-aat-layout-opbd-table.hh2
-rw-r--r--src/hb-aat-layout-trak-table.hh8
-rw-r--r--src/hb-aat-layout.cc12
-rw-r--r--src/hb-aat-map.hh8
-rw-r--r--src/hb-algs.hh192
-rw-r--r--src/hb-array.hh148
-rw-r--r--src/hb-atomic.hh26
-rw-r--r--src/hb-bimap.hh29
-rw-r--r--src/hb-bit-page.hh151
-rw-r--r--src/hb-bit-set-invertible.hh25
-rw-r--r--src/hb-bit-set.hh251
-rw-r--r--src/hb-blob.cc24
-rw-r--r--src/hb-blob.h2
-rw-r--r--src/hb-blob.hh12
-rw-r--r--src/hb-buffer-deserialize-json.hh435
-rw-r--r--src/hb-buffer-deserialize-json.rl37
-rw-r--r--src/hb-buffer-deserialize-text.hh468
-rw-r--r--src/hb-buffer-deserialize-text.rl21
-rw-r--r--src/hb-buffer-serialize.cc40
-rw-r--r--src/hb-buffer-verify.cc439
-rw-r--r--src/hb-buffer.cc421
-rw-r--r--src/hb-buffer.h211
-rw-r--r--src/hb-buffer.hh335
-rw-r--r--src/hb-cache.hh28
-rw-r--r--src/hb-cff-interp-common.hh207
-rw-r--r--src/hb-cff-interp-cs-common.hh33
-rw-r--r--src/hb-cff-interp-dict-common.hh2
-rw-r--r--src/hb-cff1-interp-cs.hh8
-rw-r--r--src/hb-cff2-interp-cs.hh115
-rw-r--r--src/hb-common.cc154
-rw-r--r--src/hb-common.h27
-rw-r--r--src/hb-config.hh39
-rw-r--r--src/hb-coretext.cc96
-rw-r--r--src/hb-cplusplus.hh221
-rw-r--r--src/hb-debug.hh9
-rw-r--r--src/hb-deprecated.h2
-rw-r--r--src/hb-directwrite.cc12
-rw-r--r--src/hb-draw.cc436
-rw-r--r--src/hb-draw.h285
-rw-r--r--src/hb-draw.hh246
-rw-r--r--src/hb-face.cc120
-rw-r--r--src/hb-face.h4
-rw-r--r--src/hb-face.hh6
-rw-r--r--src/hb-fallback-shape.cc12
-rw-r--r--src/hb-features.h.in96
-rw-r--r--src/hb-font.cc563
-rw-r--r--src/hb-font.h79
-rw-r--r--src/hb-font.hh94
-rw-r--r--src/hb-ft.cc433
-rw-r--r--src/hb-ft.h9
-rw-r--r--src/hb-glib.cc77
-rw-r--r--src/hb-gobject-enums.h.tmpl2
-rw-r--r--src/hb-gobject-structs.cc1
-rw-r--r--src/hb-gobject-structs.h4
-rw-r--r--src/hb-graphite2.cc13
-rw-r--r--src/hb-iter.hh123
-rw-r--r--src/hb-kern.hh9
-rw-r--r--src/hb-machinery.hh38
-rw-r--r--src/hb-map.cc72
-rw-r--r--src/hb-map.h12
-rw-r--r--src/hb-map.hh353
-rw-r--r--src/hb-meta.hh61
-rw-r--r--src/hb-ms-feature-ranges.cc177
-rw-r--r--src/hb-ms-feature-ranges.hh145
-rw-r--r--src/hb-multimap.hh92
-rw-r--r--src/hb-mutex.hh7
-rw-r--r--src/hb-null.hh35
-rw-r--r--src/hb-number-parser.hh8
-rw-r--r--src/hb-object.hh45
-rw-r--r--src/hb-open-file.hh4
-rw-r--r--src/hb-open-type.hh152
-rw-r--r--src/hb-ot-cff-common.hh280
-rw-r--r--src/hb-ot-cff1-table.cc79
-rw-r--r--src/hb-ot-cff1-table.hh220
-rw-r--r--src/hb-ot-cff2-table.cc60
-rw-r--r--src/hb-ot-cff2-table.hh106
-rw-r--r--src/hb-ot-cmap-table.hh643
-rw-r--r--src/hb-ot-color-cbdt-table.hh32
-rw-r--r--src/hb-ot-color-colr-table.hh184
-rw-r--r--src/hb-ot-color-colrv1-closure.hh2
-rw-r--r--src/hb-ot-color-cpal-table.hh65
-rw-r--r--src/hb-ot-color-sbix-table.hh15
-rw-r--r--src/hb-ot-color-svg-table.hh8
-rw-r--r--src/hb-ot-color.cc24
-rw-r--r--src/hb-ot-color.h4
-rw-r--r--src/hb-ot-deprecated.h15
-rw-r--r--src/hb-ot-face-table-list.hh43
-rw-r--r--src/hb-ot-face.hh3
-rw-r--r--src/hb-ot-font.cc275
-rw-r--r--src/hb-ot-glyf-table.hh1298
-rw-r--r--src/hb-ot-hmtx-table.hh279
-rw-r--r--src/hb-ot-layout-base-table.hh22
-rw-r--r--src/hb-ot-layout-common.hh2438
-rw-r--r--src/hb-ot-layout-gdef-table.hh443
-rw-r--r--src/hb-ot-layout-gpos-table.hh2946
-rw-r--r--src/hb-ot-layout-gsub-table.hh1724
-rw-r--r--src/hb-ot-layout-gsubgpos.hh1855
-rw-r--r--src/hb-ot-layout.cc649
-rw-r--r--src/hb-ot-layout.h73
-rw-r--r--src/hb-ot-layout.hh58
-rw-r--r--src/hb-ot-map.cc100
-rw-r--r--src/hb-ot-map.hh42
-rw-r--r--src/hb-ot-math-table.hh96
-rw-r--r--src/hb-ot-math.cc49
-rw-r--r--src/hb-ot-math.h36
-rw-r--r--src/hb-ot-meta-table.hh10
-rw-r--r--src/hb-ot-metrics.cc203
-rw-r--r--src/hb-ot-metrics.h5
-rw-r--r--src/hb-ot-name-language-static.hh12
-rw-r--r--src/hb-ot-name-table.hh254
-rw-r--r--src/hb-ot-name.cc53
-rw-r--r--src/hb-ot-os2-table.hh66
-rw-r--r--src/hb-ot-post-table-v2subset.hh50
-rw-r--r--src/hb-ot-post-table.hh41
-rw-r--r--src/hb-ot-shape-complex-indic-machine.hh603
-rw-r--r--src/hb-ot-shape-complex-indic-table.cc501
-rw-r--r--src/hb-ot-shape-complex-indic.hh430
-rw-r--r--src/hb-ot-shape-complex-khmer-machine.hh396
-rw-r--r--src/hb-ot-shape-complex-khmer.hh115
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.hh492
-rw-r--r--src/hb-ot-shape-complex-myanmar.hh177
-rw-r--r--src/hb-ot-shape-complex-use-machine.hh576
-rw-r--r--src/hb-ot-shape-complex-use-table.hh1283
-rw-r--r--src/hb-ot-shape-fallback.cc19
-rw-r--r--src/hb-ot-shape-normalize.cc20
-rw-r--r--src/hb-ot-shape.cc151
-rw-r--r--src/hb-ot-shape.hh10
-rw-r--r--src/hb-ot-shaper-arabic-fallback.hh (renamed from src/hb-ot-shape-complex-arabic-fallback.hh)80
-rw-r--r--src/hb-ot-shaper-arabic-joining-list.hh (renamed from src/hb-ot-shape-complex-arabic-joining-list.hh)14
-rw-r--r--src/hb-ot-shaper-arabic-pua.hh118
-rw-r--r--src/hb-ot-shaper-arabic-table.hh (renamed from src/hb-ot-shape-complex-arabic-table.hh)149
-rw-r--r--src/hb-ot-shaper-arabic-win1256.hh (renamed from src/hb-ot-shape-complex-arabic-win1256.hh)40
-rw-r--r--src/hb-ot-shaper-arabic.cc (renamed from src/hb-ot-shape-complex-arabic.cc)103
-rw-r--r--src/hb-ot-shaper-arabic.hh (renamed from src/hb-ot-shape-complex-arabic.hh)8
-rw-r--r--src/hb-ot-shaper-default.cc (renamed from src/hb-ot-shape-complex-default.cc)16
-rw-r--r--src/hb-ot-shaper-hangul.cc (renamed from src/hb-ot-shape-complex-hangul.cc)14
-rw-r--r--src/hb-ot-shaper-hebrew.cc (renamed from src/hb-ot-shape-complex-hebrew.cc)38
-rw-r--r--src/hb-ot-shaper-indic-machine.hh627
-rw-r--r--src/hb-ot-shaper-indic-machine.rl (renamed from src/hb-ot-shape-complex-indic-machine.rl)52
-rw-r--r--src/hb-ot-shaper-indic-table.cc561
-rw-r--r--src/hb-ot-shaper-indic.cc (renamed from src/hb-ot-shape-complex-indic.cc)467
-rw-r--r--src/hb-ot-shaper-indic.hh66
-rw-r--r--src/hb-ot-shaper-khmer-machine.hh428
-rw-r--r--src/hb-ot-shaper-khmer-machine.rl (renamed from src/hb-ot-shape-complex-khmer-machine.rl)54
-rw-r--r--src/hb-ot-shaper-khmer.cc (renamed from src/hb-ot-shape-complex-khmer.cc)65
-rw-r--r--src/hb-ot-shaper-myanmar-machine.hh553
-rw-r--r--src/hb-ot-shaper-myanmar-machine.rl (renamed from src/hb-ot-shape-complex-myanmar-machine.rl)83
-rw-r--r--src/hb-ot-shaper-myanmar.cc (renamed from src/hb-ot-shape-complex-myanmar.cc)139
-rw-r--r--src/hb-ot-shaper-syllabic.cc (renamed from src/hb-ot-shape-complex-syllabic.cc)43
-rw-r--r--src/hb-ot-shaper-syllabic.hh (renamed from src/hb-ot-shape-complex-syllabic.hh)15
-rw-r--r--src/hb-ot-shaper-thai.cc (renamed from src/hb-ot-shape-complex-thai.cc)28
-rw-r--r--src/hb-ot-shaper-use-machine.hh1080
-rw-r--r--src/hb-ot-shaper-use-machine.rl (renamed from src/hb-ot-shape-complex-use-machine.rl)69
-rw-r--r--src/hb-ot-shaper-use-table.hh674
-rw-r--r--src/hb-ot-shaper-use.cc (renamed from src/hb-ot-shape-complex-use.cc)71
-rw-r--r--src/hb-ot-shaper-vowel-constraints.cc (renamed from src/hb-ot-shape-complex-vowel-constraints.cc)44
-rw-r--r--src/hb-ot-shaper-vowel-constraints.hh (renamed from src/hb-ot-shape-complex-vowel-constraints.hh)8
-rw-r--r--src/hb-ot-shaper.hh (renamed from src/hb-ot-shape-complex.hh)107
-rw-r--r--src/hb-ot-stat-table.hh276
-rw-r--r--src/hb-ot-tag-table.hh3607
-rw-r--r--src/hb-ot-tag.cc133
-rw-r--r--src/hb-ot-var-avar-table.hh81
-rw-r--r--src/hb-ot-var-common.hh84
-rw-r--r--src/hb-ot-var-fvar-table.hh161
-rw-r--r--src/hb-ot-var-gvar-table.hh338
-rw-r--r--src/hb-ot-var-hvar-table.hh39
-rw-r--r--src/hb-ot-var-mvar-table.hh2
-rw-r--r--src/hb-ot-var.cc7
-rw-r--r--src/hb-ot-var.h2
-rw-r--r--src/hb-pool.hh12
-rw-r--r--src/hb-priority-queue.hh36
-rw-r--r--src/hb-repacker.hh1274
-rw-r--r--src/hb-sanitize.hh30
-rw-r--r--src/hb-serialize.hh195
-rw-r--r--src/hb-set-digest.hh65
-rw-r--r--src/hb-set.cc94
-rw-r--r--src/hb-set.h16
-rw-r--r--src/hb-set.hh40
-rw-r--r--src/hb-shape-plan.cc28
-rw-r--r--src/hb-shape-plan.h4
-rw-r--r--src/hb-shape-plan.hh3
-rw-r--r--src/hb-shape.cc53
-rw-r--r--src/hb-shaper.cc16
-rw-r--r--src/hb-static.cc55
-rw-r--r--src/hb-style.cc16
-rw-r--r--src/hb-style.h4
-rw-r--r--src/hb-subset-accelerator.hh121
-rw-r--r--src/hb-subset-cff-common.cc11
-rw-r--r--src/hb-subset-cff-common.hh614
-rw-r--r--src/hb-subset-cff1.cc92
-rw-r--r--src/hb-subset-cff2.cc94
-rw-r--r--src/hb-subset-input.cc251
-rw-r--r--src/hb-subset-input.hh59
-rw-r--r--src/hb-subset-plan.cc985
-rw-r--r--src/hb-subset-plan.hh156
-rw-r--r--src/hb-subset-repacker.cc58
-rw-r--r--src/hb-subset-repacker.h81
-rw-r--r--src/hb-subset.cc400
-rw-r--r--src/hb-subset.h86
-rw-r--r--src/hb-ucd-table.hh7469
-rw-r--r--src/hb-ucd.cc16
-rw-r--r--src/hb-unicode-emoji-table.hh71
-rw-r--r--src/hb-unicode.cc40
-rw-r--r--src/hb-unicode.h8
-rw-r--r--src/hb-unicode.hh7
-rw-r--r--src/hb-uniscribe.cc9
-rw-r--r--src/hb-vector.hh302
-rw-r--r--src/hb-version.h8
-rw-r--r--src/hb.hh8
-rw-r--r--src/main.cc99
-rw-r--r--src/meson.build236
-rw-r--r--src/ms-use/IndicPositionalCategory-Additional.txt15
-rw-r--r--src/ms-use/IndicShapingInvalidCluster.txt198
-rw-r--r--src/ms-use/IndicSyllabicCategory-Additional.txt91
-rwxr-xr-xsrc/sample.py2
-rw-r--r--src/test-algs.cc15
-rw-r--r--src/test-array.cc3
-rw-r--r--src/test-buffer-serialize.cc14
-rw-r--r--src/test-iter.cc102
-rw-r--r--src/test-machinery.cc46
-rw-r--r--src/test-map.cc216
-rw-r--r--src/test-multimap.cc59
-rw-r--r--src/test-ot-glyphname.cc2
-rw-r--r--src/test-priority-queue.cc8
-rw-r--r--src/test-repacker.cc1218
-rw-r--r--src/test-serialize.cc52
-rw-r--r--src/test-set.cc32
-rw-r--r--src/test-use-table.cc18
-rw-r--r--src/test-vector.cc54
-rwxr-xr-xsrc/update-unicode-tables.make24
-rw-r--r--subprojects/.gitignore2
-rw-r--r--subprojects/cairo.wrap5
-rw-r--r--subprojects/freetype2.wrap14
-rw-r--r--subprojects/glib.wrap17
-rw-r--r--subprojects/google-benchmark.wrap17
-rw-r--r--subprojects/ttf-parser.wrap5
-rw-r--r--subprojects/zlib.wrap12
-rw-r--r--test/Makefile.am2
-rw-r--r--test/api/Makefile.am10
-rw-r--r--test/api/fonts/base2.ttfbin0 -> 5236 bytes
-rw-r--r--test/api/fonts/nameID.override.expected.ttfbin0 -> 168012 bytes
-rw-r--r--test/api/fonts/notosansitalic.ttfbin0 -> 1464 bytes
-rw-r--r--test/api/fonts/repacker_expected.otfbin0 -> 1400 bytes
-rw-r--r--test/api/hb-test.h15
-rw-r--r--test/api/meson.build3
-rw-r--r--test/api/test-baseline.c53
-rw-r--r--test/api/test-be-glyph-advance.c101
-rw-r--r--test/api/test-be-num-glyphs.c73
-rw-r--r--test/api/test-c.c2
-rw-r--r--test/api/test-cplusplus.cc99
-rw-r--r--test/api/test-draw.c572
-rw-r--r--test/api/test-ot-face.c39
-rw-r--r--test/api/test-ot-math.c84
-rw-r--r--test/api/test-ot-metrics-tt-var.c4
-rw-r--r--test/api/test-ot-name.c7
-rw-r--r--test/api/test-ot-tag.c2
-rw-r--r--test/api/test-set.c130
-rw-r--r--test/api/test-style.c29
-rw-r--r--test/api/test-subset-nameids.c41
-rw-r--r--test/api/test-subset-repacker.c225
-rw-r--r--test/api/test-subset.c76
-rw-r--r--test/api/test-unicode.c14
-rw-r--r--test/api/test-var-coords.c2
-rw-r--r--test/fuzzing/Makefile.am2
-rw-r--r--test/fuzzing/README21
-rw-r--r--test/fuzzing/README.md17
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152bin0 -> 655 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464bin0 -> 17004 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584bin0 -> 486280 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040bin0 -> 472 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800bin0 -> 140 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512bin0 -> 1603 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040bin0 -> 175945 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664bin0 -> 66032 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4979711393005568bin0 -> 349 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760bin0 -> 123110 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5205038086094848bin0 -> 129192 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192bin0 -> 83705 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248bin0 -> 3161 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5422577634377728bin0 -> 1700 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5549945449480192bin0 -> 562733 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296bin0 -> 220551 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672bin0 -> 1543 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608bin0 -> 427854 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648bin0 -> 191 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216bin0 -> 131411 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416bin0 -> 161424 bytes
-rw-r--r--test/fuzzing/fonts/crash-d223bc42a8226c4d655c417d63d9a76760d05985bin0 -> 316 bytes
-rw-r--r--test/fuzzing/fonts/sbix-extents.ttfbin0 -> 582 bytes
-rw-r--r--test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448bin0 -> 423 bytes
-rw-r--r--test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344bin0 -> 921 bytes
-rw-r--r--test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728bin0 -> 358596 bytes
-rw-r--r--test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4bin0 -> 358596 bytes
-rw-r--r--test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774bin0 -> 358596 bytes
-rw-r--r--test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527bin0 -> 358596 bytes
-rw-r--r--test/fuzzing/graphs/noto_nastaliq_urdubin0 -> 358596 bytes
-rw-r--r--test/fuzzing/hb-draw-fuzzer.cc123
-rw-r--r--test/fuzzing/hb-fuzzer.hh16
-rw-r--r--test/fuzzing/hb-repacker-fuzzer.cc145
-rw-r--r--test/fuzzing/hb-set-fuzzer.cc4
-rw-r--r--test/fuzzing/hb-shape-fuzzer.cc4
-rw-r--r--test/fuzzing/hb-subset-fuzzer.cc2
-rw-r--r--test/fuzzing/meson.build28
-rw-r--r--test/fuzzing/run-repacker-fuzzer-tests.py68
-rw-r--r--test/meson.build1
-rw-r--r--test/shape/Makefile.am1
-rw-r--r--test/shape/README.md4
-rw-r--r--test/shape/data/aots/Makefile.sources3
-rw-r--r--test/shape/data/aots/hb-aots-tester.cpp6
-rw-r--r--test/shape/data/aots/tests/classdef1.tests2
-rw-r--r--test/shape/data/aots/tests/classdef1_empty.tests2
-rw-r--r--test/shape/data/aots/tests/classdef1_multiple.tests2
-rw-r--r--test/shape/data/aots/tests/classdef1_single.tests2
-rw-r--r--test/shape/data/aots/tests/classdef2.tests2
-rw-r--r--test/shape/data/aots/tests/classdef2_empty.tests2
-rw-r--r--test/shape/data/aots/tests/classdef2_multiple.tests2
-rw-r--r--test/shape/data/aots/tests/classdef2_single.tests2
-rw-r--r--test/shape/data/aots/tests/cmap0.tests2
-rw-r--r--test/shape/data/aots/tests/cmap10.tests4
-rw-r--r--test/shape/data/aots/tests/cmap12.tests2
-rw-r--r--test/shape/data/aots/tests/cmap2.tests2
-rw-r--r--test/shape/data/aots/tests/cmap4.tests12
-rw-r--r--test/shape/data/aots/tests/cmap6.tests4
-rw-r--r--test/shape/data/aots/tests/cmap8.tests2
-rw-r--r--test/shape/data/aots/tests/gpos1_1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gpos1_1_simple.tests8
-rw-r--r--test/shape/data/aots/tests/gpos1_2.tests2
-rw-r--r--test/shape/data/aots/tests/gpos1_2_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gpos2_1.tests4
-rw-r--r--test/shape/data/aots/tests/gpos2_1_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos2_1_next_glyph.tests4
-rw-r--r--test/shape/data/aots/tests/gpos2_1_simple.tests4
-rw-r--r--test/shape/data/aots/tests/gpos2_2.tests10
-rw-r--r--test/shape/data/aots/tests/gpos3.tests22
-rw-r--r--test/shape/data/aots/tests/gpos3_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos4_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos4_multiple_anchors.tests2
-rw-r--r--test/shape/data/aots/tests/gpos4_simple.tests10
-rw-r--r--test/shape/data/aots/tests/gpos5.tests4
-rw-r--r--test/shape/data/aots/tests/gpos6.tests6
-rw-r--r--test/shape/data/aots/tests/gpos7_1.tests4
-rw-r--r--test/shape/data/aots/tests/gpos9.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gpos_chaining1_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gpos_chaining2_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining3_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_chaining3_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gpos_chaining3_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context1_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context1_expansion.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context1_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context1_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context1_simple.tests6
-rw-r--r--test/shape/data/aots/tests/gpos_context1_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context2_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context2_classes.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context2_expansion.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context2_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context2_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context2_simple.tests6
-rw-r--r--test/shape/data/aots/tests/gpos_context2_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context3_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context3_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context3_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gpos_context3_simple.tests4
-rw-r--r--test/shape/data/aots/tests/gpos_context3_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub1_1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub1_1_modulo.tests2
-rw-r--r--test/shape/data/aots/tests/gsub1_1_simple.tests2
-rw-r--r--test/shape/data/aots/tests/gsub1_2_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub1_2_simple.tests2
-rw-r--r--test/shape/data/aots/tests/gsub2_1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests2
-rw-r--r--test/shape/data/aots/tests/gsub2_1_simple.tests4
-rw-r--r--test/shape/data/aots/tests/gsub3_1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub3_1_multiple.tests2
-rw-r--r--test/shape/data/aots/tests/gsub3_1_simple.tests2
-rw-r--r--test/shape/data/aots/tests/gsub4_1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests4
-rw-r--r--test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests2
-rw-r--r--test/shape/data/aots/tests/gsub4_1_simple.tests2
-rw-r--r--test/shape/data/aots/tests/gsub7.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gsub_chaining1_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gsub_chaining2_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining3_boundary.tests8
-rw-r--r--test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_chaining3_simple.tests22
-rw-r--r--test/shape/data/aots/tests/gsub_chaining3_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context1_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context1_expansion.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context1_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context1_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context1_simple.tests6
-rw-r--r--test/shape/data/aots/tests/gsub_context1_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context2_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context2_classes.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context2_expansion.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context2_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context2_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context2_simple.tests6
-rw-r--r--test/shape/data/aots/tests/gsub_context2_successive.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context3_boundary.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context3_lookupflag.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context3_next_glyph.tests2
-rw-r--r--test/shape/data/aots/tests/gsub_context3_simple.tests4
-rw-r--r--test/shape/data/aots/tests/gsub_context3_successive.tests2
-rw-r--r--test/shape/data/aots/tests/lookupflag_ignore_attach.tests10
-rw-r--r--test/shape/data/aots/tests/lookupflag_ignore_base.tests4
-rw-r--r--test/shape/data/aots/tests/lookupflag_ignore_combination.tests6
-rw-r--r--test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests6
-rw-r--r--test/shape/data/aots/tests/lookupflag_ignore_marks.tests2
-rw-r--r--test/shape/data/in-house/Makefile.am14
-rw-r--r--test/shape/data/in-house/Makefile.sources12
-rw-r--r--test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttfbin0 -> 1076 bytes
-rw-r--r--test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttfbin0 -> 1320 bytes
-rw-r--r--test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttfbin0 -> 1400 bytes
-rw-r--r--test/shape/data/in-house/fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttfbin0 -> 1904 bytes
-rw-r--r--test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttfbin0 -> 3216 bytes
-rw-r--r--test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttfbin0 -> 5464 bytes
-rw-r--r--test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttfbin0 -> 6400 bytes
-rw-r--r--test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttfbin0 -> 1028 bytes
-rw-r--r--test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttfbin0 -> 1656 bytes
-rw-r--r--test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttfbin0 -> 2544 bytes
-rw-r--r--test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttfbin0 -> 2312 bytes
-rw-r--r--test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttfbin0 -> 3000 bytes
-rw-r--r--test/shape/data/in-house/fonts/FallbackPlus-Javanese-no-GDEF.otfbin0 -> 4776 bytes
-rw-r--r--test/shape/data/in-house/fonts/NotoNastaliqUrdu-Regular.ttfbin0 -> 457312 bytes
-rw-r--r--test/shape/data/in-house/fonts/SimpArabicTest.ttfbin0 -> 17168 bytes
-rw-r--r--test/shape/data/in-house/fonts/TradArabicTest.ttfbin0 -> 58132 bytes
-rw-r--r--test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttfbin0 -> 2512 bytes
-rw-r--r--test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttfbin0 -> 1292 bytes
-rw-r--r--test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttfbin0 -> 1180 bytes
-rw-r--r--test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttfbin0 -> 29284 bytes
-rw-r--r--test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttfbin0 -> 1076 bytes
-rw-r--r--test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttfbin0 -> 6260 bytes
-rw-r--r--test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttfbin0 -> 8324 bytes
-rw-r--r--test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttfbin0 -> 90140 bytes
-rw-r--r--test/shape/data/in-house/meson.build12
-rw-r--r--test/shape/data/in-house/tests/arabic-fallback-shaping.tests10
-rw-r--r--test/shape/data/in-house/tests/arabic-phags-pa.tests14
-rw-r--r--test/shape/data/in-house/tests/collections.tests6
-rw-r--r--test/shape/data/in-house/tests/context-matching.tests2
-rw-r--r--test/shape/data/in-house/tests/coretext.tests1
-rw-r--r--test/shape/data/in-house/tests/cursive-positioning.tests11
-rw-r--r--test/shape/data/in-house/tests/directwrite.tests1
-rw-r--r--test/shape/data/in-house/tests/emoji-clusters.tests86
-rw-r--r--test/shape/data/in-house/tests/glyph-props-no-gdef.tests1
-rw-r--r--test/shape/data/in-house/tests/hebrew-diacritics.tests31
-rw-r--r--test/shape/data/in-house/tests/indic-decompose.tests2
-rw-r--r--test/shape/data/in-house/tests/indic-feature-order.tests1
-rw-r--r--test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests15
-rw-r--r--test/shape/data/in-house/tests/indic-special-cases.tests5
-rw-r--r--test/shape/data/in-house/tests/indic-syllable.tests1
-rw-r--r--test/shape/data/in-house/tests/khmer-misc.tests2
-rw-r--r--test/shape/data/in-house/tests/ligature-id.tests1
-rw-r--r--test/shape/data/in-house/tests/macos.tests18
-rw-r--r--test/shape/data/in-house/tests/myanmar-misc.tests1
-rw-r--r--test/shape/data/in-house/tests/nested-mark-filtering-sets.tests4
-rw-r--r--test/shape/data/in-house/tests/sara-am.tests52
-rw-r--r--test/shape/data/in-house/tests/spaces.tests34
-rw-r--r--test/shape/data/in-house/tests/uniscribe.tests1
-rw-r--r--test/shape/data/in-house/tests/unsafe-to-concat.tests1
-rw-r--r--test/shape/data/in-house/tests/use-javanese.tests54
-rw-r--r--test/shape/data/in-house/tests/use-syllable.tests2
-rw-r--r--test/shape/data/in-house/tests/use.tests2
-rw-r--r--test/shape/data/in-house/tests/vertical.tests2
-rw-r--r--test/shape/meson.build29
-rwxr-xr-xtest/shape/record-test.sh10
-rwxr-xr-xtest/shape/run-tests.py19
-rwxr-xr-xtest/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt8
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt28
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt695
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt48
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt188
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt18
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt1
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt10
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt6
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt8
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt4
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt8
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt5
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt14
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt11
-rw-r--r--test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt98
-rw-r--r--test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt1
-rw-r--r--test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt3
-rw-r--r--test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt8
-rw-r--r--test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt53
-rw-r--r--test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt1
-rw-r--r--test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt10
-rw-r--r--test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt4
-rw-r--r--test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt16
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt40
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt11
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt59
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt131
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt139
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt53
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt14
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt36
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt58
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt119
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt215
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt33
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt17
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt8
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt36
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt5
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt8
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt45
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt14
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt16
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt185
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt185
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt1367
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt8
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt34
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt7
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt170
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt170
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt1156
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt9
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt38
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt9
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt22
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt152
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt20
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt7
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt40
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt14
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt9
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt188
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt306
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt5
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt188
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt15
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt65
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt36
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt14
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt254
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt28
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt34
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt8
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt170
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt4390
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt41
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt41
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt17
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt18
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt162
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt41
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt42
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt41
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt43
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt23
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt11
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt3
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt1
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt64
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt44
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt4
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt12
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt5
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE19
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt38
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt13
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt10
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt14
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt2
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt6
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt385
-rw-r--r--test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt287
-rw-r--r--test/shape/texts/in-house/shaper-khmer/misc.txt89
-rw-r--r--test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt4
-rw-r--r--test/shape/texts/in-house/shaper-khmer/other-marks.txt7
-rw-r--r--test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt7
-rw-r--r--test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt1
-rw-r--r--test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt34
-rw-r--r--test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt20
-rw-r--r--test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt11
-rw-r--r--test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt16
-rw-r--r--test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt11
-rw-r--r--test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt20
-rw-r--r--test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt612
-rw-r--r--test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt2
-rw-r--r--test/shape/texts/in-house/shaper-use/script-batak/misc.txt9
-rw-r--r--test/shape/texts/in-house/shaper-use/script-buginese/misc.txt70
-rw-r--r--test/shape/texts/in-house/shaper-use/script-cham/misc.txt3
-rw-r--r--test/shape/texts/in-house/shaper-use/script-javanese/misc.txt54
-rw-r--r--test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt6
-rw-r--r--test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt36
-rw-r--r--test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt2
-rw-r--r--test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt23
-rw-r--r--test/subset/data/Makefile.am11
-rw-r--r--test/subset/data/Makefile.sources13
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otfbin0 -> 5676 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otfbin0 -> 4776 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otfbin0 -> 4588 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otfbin0 -> 4764 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otfbin0 -> 4128 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otfbin0 -> 3904 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otfbin0 -> 3828 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otfbin0 -> 3800 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otfbin0 -> 5676 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otfbin0 -> 4776 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otfbin0 -> 4584 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otfbin0 -> 4744 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otfbin0 -> 4128 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otfbin0 -> 3892 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otfbin0 -> 3812 bytes
-rw-r--r--test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otfbin0 -> 3780 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttfbin222756 -> 222684 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttfbin191632 -> 191560 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttfbin191584 -> 191512 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttfbin222756 -> 222684 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttfbin229748 -> 229676 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttfbin223452 -> 223380 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttfbin220948 -> 220876 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttfbin222496 -> 222424 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttfbin222756 -> 222684 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttfbin222756 -> 222684 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttfbin222756 -> 222684 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttfbin223352 -> 223280 bytes
-rw-r--r--test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttfbin222804 -> 222732 bytes
-rw-r--r--test/subset/data/expected/colr_glyphs/BungeeColor-Regular.default.41.ttfbin0 -> 1664 bytes
-rw-r--r--test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints-retain-gids.41.ttfbin0 -> 3384 bytes
-rw-r--r--test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints.41.ttfbin0 -> 1656 bytes
-rw-r--r--test/subset/data/expected/colr_glyphs/BungeeColor-Regular.retain-gids.41.ttfbin0 -> 3392 bytes
-rw-r--r--test/subset/data/expected/colr_with_components/colr-table.default.6B.ttfbin4260 -> 4320 bytes
-rw-r--r--test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttfbin4984 -> 5044 bytes
-rw-r--r--test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttfbin4260 -> 4320 bytes
-rw-r--r--test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttfbin4984 -> 5044 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 4800 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 2452 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttfbin0 -> 2856 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttfbin0 -> 2856 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 4560 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttfbin0 -> 2484 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttfbin0 -> 2828 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 3932 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttfbin0 -> 2484 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttfbin0 -> 2828 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttfbin0 -> 2972 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 4140 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttfbin0 -> 2600 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttfbin0 -> 2928 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttfbin0 -> 2836 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 3912 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttfbin0 -> 2464 bytes
-rw-r--r--test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttfbin0 -> 2808 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 9704 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttfbin3876 -> 3864 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 9704 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttfbin0 -> 3476 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttfbin0 -> 3476 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 8700 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttfbin0 -> 3476 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttfbin0 -> 3948 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 6584 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttfbin0 -> 3476 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttfbin0 -> 3948 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttfbin0 -> 3856 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 9548 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttfbin0 -> 3752 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttfbin0 -> 4292 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttfbin0 -> 3456 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttfbin0 -> 6564 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttfbin0 -> 3456 bytes
-rw-r--r--test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttfbin0 -> 3928 bytes
-rw-r--r--test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttfbin0 -> 114200 bytes
-rw-r--r--test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttfbin0 -> 114300 bytes
-rw-r--r--test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttfbin0 -> 114200 bytes
-rw-r--r--test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttfbin0 -> 114300 bytes
-rw-r--r--test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttfbin281092 -> 280056 bytes
-rw-r--r--test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.retain-all-codepoint.wght=400.ttfbin0 -> 1660624 bytes
-rw-r--r--test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.notdef-outline.retain-all-codepoint.wght=400.ttfbin0 -> 1660668 bytes
-rw-r--r--test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttfbin0 -> 6760 bytes
-rw-r--r--test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttfbin0 -> 6712 bytes
-rw-r--r--test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttfbin0 -> 6440 bytes
-rw-r--r--test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttfbin0 -> 6392 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otfbin2152 -> 2148 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otfbin2028 -> 2024 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otfbin4012 -> 4008 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otfbin1440 -> 1436 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otfbin1320 -> 1316 bytes
-rw-r--r--test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otfbin4012 -> 4008 bytes
-rw-r--r--test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttfbin0 -> 142456 bytes
-rw-r--r--test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttfbin0 -> 142456 bytes
-rw-r--r--test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttfbin0 -> 134344 bytes
-rw-r--r--test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttfbin0 -> 145620 bytes
-rw-r--r--test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttfbin0 -> 134472 bytes
-rw-r--r--test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttfbin120236 -> 120020 bytes
-rw-r--r--test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttfbin132480 -> 132264 bytes
-rw-r--r--test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttfbin120236 -> 120020 bytes
-rw-r--r--test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttfbin49248 -> 49244 bytes
-rw-r--r--test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttfbin29468 -> 29464 bytes
-rw-r--r--test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttfbin49248 -> 49244 bytes
-rw-r--r--test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttfbin174308 -> 173756 bytes
-rw-r--r--test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttfbin99288 -> 99020 bytes
-rw-r--r--test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttfbin174608 -> 174056 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otfbin2256 -> 2252 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otfbin2224 -> 2220 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otfbin4008 -> 4004 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otfbin1460 -> 1456 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otfbin1416 -> 1412 bytes
-rw-r--r--test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otfbin4008 -> 4004 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttfbin11372 -> 19032 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttfbin17732 -> 25608 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttfbin3512 -> 8040 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttfbin12360 -> 22776 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,6D2.ttfbin0 -> 14048 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttfbin19432 -> 27772 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttfbin0 -> 543364 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttfbin18208 -> 25868 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttfbin23792 -> 31676 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttfbin9160 -> 13688 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttfbin18164 -> 28580 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,6D2.ttfbin0 -> 19948 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttfbin25484 -> 33824 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttfbin0 -> 543364 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttfbin0 -> 17564 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttfbin0 -> 24532 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttfbin0 -> 7776 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttfbin0 -> 23232 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttfbin0 -> 14292 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttfbin0 -> 26124 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttfbin0 -> 542328 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttfbin0 -> 24224 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttfbin0 -> 30432 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttfbin0 -> 13380 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttfbin0 -> 28888 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttfbin0 -> 20132 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttfbin0 -> 31984 bytes
-rw-r--r--test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttfbin0 -> 542360 bytes
-rw-r--r--test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttfbin412764 -> 410092 bytes
-rw-r--r--test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttfbin437592 -> 434920 bytes
-rw-r--r--test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttfbin412764 -> 410092 bytes
-rw-r--r--test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttfbin415140 -> 412468 bytes
-rw-r--r--test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttfbin131672 -> 129952 bytes
-rw-r--r--test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttfbin153648 -> 151928 bytes
-rw-r--r--test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttfbin134776 -> 133056 bytes
-rw-r--r--test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttfbin1038580 -> 1033528 bytes
-rw-r--r--test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttfbin1091356 -> 1086304 bytes
-rw-r--r--test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttfbin1038828 -> 1033776 bytes
-rw-r--r--test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttfbin1053656 -> 1048716 bytes
-rw-r--r--test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttfbin0 -> 417604 bytes
-rw-r--r--test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttfbin0 -> 436712 bytes
-rw-r--r--test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttfbin0 -> 417604 bytes
-rw-r--r--test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttfbin0 -> 417780 bytes
-rw-r--r--test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttfbin0 -> 417620 bytes
-rw-r--r--test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttfbin0 -> 6804 bytes
-rw-r--r--test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttfbin0 -> 6804 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.c30,c36,c40,c4d.ttfbin0 -> 10848 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttfbin0 -> 572104 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.c30,c36,c40,c4d.ttfbin0 -> 11280 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttfbin0 -> 607752 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.c30,c36,c40,c4d.ttfbin0 -> 10928 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttfbin0 -> 572184 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.c30,c36,c40,c4d.ttfbin0 -> 16868 bytes
-rw-r--r--test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttfbin0 -> 572116 bytes
-rw-r--r--test/subset/data/fonts/32bit_var_store.otfbin0 -> 5664 bytes
-rw-r--r--test/subset/data/fonts/BungeeColor-Regular.ttfbin0 -> 75348 bytes
-rw-r--r--test/subset/data/fonts/Caudex-Regular.ttfbin0 -> 466324 bytes
-rw-r--r--test/subset/data/fonts/MPLUS1-Variable.ttfbin0 -> 4133100 bytes
-rw-r--r--test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttfbin459600 -> 589224 bytes
-rw-r--r--test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttfbin570552 -> 1060612 bytes
-rw-r--r--test/subset/data/fonts/NotoSansDevanagari-Regular.ttf (renamed from perf/fonts/NotoSansDevanagari-Regular.ttf)bin212740 -> 212740 bytes
-rw-r--r--test/subset/data/fonts/NotoSansNewa-Regular.ttfbin0 -> 150892 bytes
-rw-r--r--test/subset/data/fonts/Roboto-Variable.ABC.ttfbin0 -> 13480 bytes
-rw-r--r--test/subset/data/fonts/Roboto-Variable.composite.ttfbin0 -> 9576 bytes
-rw-r--r--test/subset/data/fonts/Roboto-Variable.ttfbin0 -> 477420 bytes
-rw-r--r--test/subset/data/fonts/RobotoFlex-Variable.ttfbin0 -> 1755856 bytes
-rw-r--r--test/subset/data/fonts/SpectralSC-ExtraLightItalic.ttfbin0 -> 275612 bytes
-rw-r--r--test/subset/data/fonts/SreeKrushnadevaraya-Regular.ttfbin0 -> 612636 bytes
-rw-r--r--test/subset/data/fonts/colr-table.ttfbin26952 -> 27328 bytes
-rw-r--r--test/subset/data/profiles/filter-scripts-features.2.txt2
-rw-r--r--test/subset/data/profiles/filter-scripts-features.txt2
-rw-r--r--test/subset/data/profiles/filter-scripts.txt1
-rw-r--r--test/subset/data/profiles/no-scripts.txt1
-rw-r--r--test/subset/data/tests/32bit_var_store.tests16
-rw-r--r--test/subset/data/tests/colr_glyphs.tests11
-rw-r--r--test/subset/data/tests/full-font.tests5
-rw-r--r--test/subset/data/tests/full_instance.tests13
-rw-r--r--test/subset/data/tests/instance_feature_variations.tests12
-rw-r--r--test/subset/data/tests/instantiate_glyf.tests13
-rw-r--r--test/subset/data/tests/layout.context_format2.tests9
-rw-r--r--test/subset/data/tests/layout.drop_feature.tests10
-rw-r--r--test/subset/data/tests/layout.notonastaliqurdu.tests3
-rw-r--r--test/subset/data/tests/math_coverage_offset.tests12
-rw-r--r--test/subset/data/tests/pin_all_at_default.tests12
-rw-r--r--test/subset/data/tests/post.tests12
-rwxr-xr-xtest/subset/generate-expected-outputs.py24
-rw-r--r--test/subset/meson.build23
-rwxr-xr-xtest/subset/run-tests.py19
-rw-r--r--test/subset/subset_test_suite.py32
-rw-r--r--test/threads/Makefile.am17
-rw-r--r--test/threads/hb-shape-threads.cc210
-rw-r--r--test/threads/hb-subset-threads.cc180
-rw-r--r--test/threads/meson.build28
-rw-r--r--util/Makefile.sources3
-rw-r--r--util/ansi-print.hh26
-rw-r--r--util/font-options.hh32
-rw-r--r--util/hb-ot-shape-closure.cc6
-rw-r--r--util/hb-shape.cc128
-rw-r--r--util/hb-subset.cc168
-rw-r--r--util/helper-cairo-ansi.hh25
-rw-r--r--util/helper-cairo-ft.hh120
-rw-r--r--util/helper-cairo-user.hh316
-rw-r--r--util/helper-cairo.hh120
-rw-r--r--util/main-font-text.hh14
-rw-r--r--util/meson.build3
-rw-r--r--util/shape-consumer.hh4
-rw-r--r--util/shape-options.hh187
-rw-r--r--util/shape-output.hh159
-rw-r--r--util/text-options.hh44
1133 files changed, 77493 insertions, 43125 deletions
diff --git a/.ci/build-win32.sh b/.ci/build-win32.sh
index 39ed42cb3..067e2224c 100755
--- a/.ci/build-win32.sh
+++ b/.ci/build-win32.sh
@@ -3,12 +3,12 @@ set -e
meson --cross-file=.ci/win32-cross-file.txt \
--wrap-mode=forcefallback \
- --buildtype=release \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
+ -Dcairo:freetype=disabled \
-Dglib=enabled \
- -Dfreetype=enabled \
+ -Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
-Dcairo=enabled \
diff --git a/.ci/build-win64.sh b/.ci/build-win64.sh
index 652410a97..946d245a6 100644
--- a/.ci/build-win64.sh
+++ b/.ci/build-win64.sh
@@ -3,12 +3,12 @@ set -e
meson --cross-file=.ci/win64-cross-file.txt \
--wrap-mode=forcefallback \
- --buildtype=release \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
+ -Dcairo:freetype=disabled \
-Dglib=enabled \
- -Dfreetype=enabled \
+ -Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
-Dcairo=enabled \
diff --git a/.ci/deploy-docs.sh b/.ci/deploy-docs.sh
index b644dfe14..2b3f9f232 100755
--- a/.ci/deploy-docs.sh
+++ b/.ci/deploy-docs.sh
@@ -3,8 +3,6 @@
set -x
set -o errexit -o nounset
-TAG="$(git describe --exact-match --match "[0-9]*" HEAD 2>/dev/null || true)"
-
DOCSDIR=build-docs
REVISION=$(git rev-parse --short HEAD)
@@ -17,8 +15,8 @@ cp ../build/docs/html/* .
git init
git branch -m main
-git config user.name "Travis CI"
-git config user.email "travis@harfbuzz.org"
+git config user.name "CI"
+git config user.email "harfbuzz-admin@googlegroups.com"
set +x
echo "git remote add upstream \"https://\$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git\""
git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git"
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 84f59bb89..b013b5576 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -53,14 +53,14 @@ jobs:
fedora-valgrind:
docker:
- - image: fedora:33
+ - image: fedora:36
steps:
- checkout
- run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true
- run: meson build --buildtype=debugoptimized
- run: ninja -Cbuild -j9
# TOOD: increase timeouts and remove --no-suite=slow
- - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs
+ - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1))
alpine:
docker:
@@ -68,7 +68,7 @@ jobs:
steps:
- checkout
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
- - run: pip3 install meson==0.52.0
+ - run: pip3 install meson==0.56.0
- run: meson build --buildtype=minsize
- run: ninja -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs
@@ -88,30 +88,55 @@ jobs:
- run: clang -c src/harfbuzz.cc -DHB_NO_MT
- run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT
- sanitizers:
+ asan-ubsan:
docker:
- image: ubuntu:20.04
steps:
- checkout
- run: apt update || true
- - run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils meson pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- # asan+ubsan
- - run: rm -rf build && meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
+ - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+ - run: pip3 install meson==0.56.0
+ - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
- # tsan
- - run: rm -rf build && meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
+
+ tsan:
+ docker:
+ - image: ubuntu:20.04
+ steps:
+ - checkout
+ - run: apt update || true
+ - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+ - run: pip3 install meson==0.56.0
+ - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+
+ msan:
+ docker:
+ - image: ubuntu:20.04
+ steps:
+ - checkout
+ - run: apt update || true
+ - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+ - run: pip3 install meson==0.56.0
# msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
- - run: rm -rf build && meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
+ - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
- - run: clang -c src/harfbuzz.cc src/hb-subset*.cc -DHB_NO_MT -Werror -std=c++2a
+
+ clang-cxx2a:
+ docker:
+ - image: ubuntu:20.04
+ steps:
+ - checkout
+ - run: apt update || true
+ - run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils
+ - run: clang -c src/harfbuzz-subset.cc -DHB_NO_MT -Werror -std=c++2a
crossbuild-win32:
executor: win32-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-i686 zip
- - run: pip3 install meson==0.56.0 --upgrade
+ - run: pip3 install meson==0.60.0
- run: .ci/build-win32.sh
- store_artifacts:
path: harfbuzz-win32.zip
@@ -134,7 +159,7 @@ jobs:
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-x86-64 zip
- - run: pip3 install meson==0.56.0 --upgrade
+ - run: pip3 install meson==0.60.0
- run: bash .ci/build-win64.sh
- store_artifacts:
path: harfbuzz-win64.zip
@@ -174,7 +199,10 @@ workflows:
- fedora-valgrind
- alpine
#- archlinux
- - sanitizers
+ - asan-ubsan
+ - tsan
+ - msan
+ - clang-cxx2a
- crossbuild-win32:
filters: # must have filter or won't work as a dependency
tags:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..5ace4600a
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/arm-ci.yml b/.github/workflows/arm-ci.yml
new file mode 100644
index 000000000..3df13163f
--- /dev/null
+++ b/.github/workflows/arm-ci.yml
@@ -0,0 +1,25 @@
+name: arm
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+permissions:
+ contents: read
+
+jobs:
+ arm-none-eabi:
+ runs-on: ubuntu-22.04
+ container:
+ image: devkitpro/devkitarm:latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Configure CMake
+ run: |
+ cmake -S . -B build \
+ -DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake
+ - name: Build
+ run: make CXX_FLAGS="-w -DHB_NO_MT"
+ working-directory: build
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index a9d4eb05c..07e4cd575 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -17,7 +17,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
diff --git a/.github/workflows/configs-build.yml b/.github/workflows/configs-build.yml
new file mode 100644
index 000000000..b81ce92b0
--- /dev/null
+++ b/.github/workflows/configs-build.yml
@@ -0,0 +1,27 @@
+name: configs-ci
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: install dependencies
+ run: sudo apt-get install gcc
+ - name: HB_DISABLE_DEPRECATED
+ run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_DISABLE_DEPRECATED
+ - name: HB_MINI
+ run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_MINI
+ - name: HB_LEAN
+ run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_LEAN
+ - name: HB_TINY
+ run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_TINY
diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml
index 6fcb4e5ef..e9fc5435e 100644
--- a/.github/workflows/coverity-scan.yml
+++ b/.github/workflows/coverity-scan.yml
@@ -4,17 +4,20 @@ on:
schedule:
- cron: '0 10 * * *' # Daily at 10:00 UTC
+permissions:
+ contents: read
+
jobs:
latest:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev
- name: Download Coverity
run: |
- wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=behdad/harfbuzz" -O cov-analysis-linux64.tar.gz
+ wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=HarfBuzz" -O cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
env:
@@ -28,12 +31,12 @@ jobs:
- name: submit to coverity
run: |
curl \
- --form project=behdad/harfbuzz \
+ --form project=HarfBuzz \
--form token=$TOKEN \
--form email=harfbuzz-bots-chatter@googlegroups.com \
--form file=@harfbuzz.tgz \
--form version=trunk \
--form description="`git rev-parse --short HEAD`" \
- https://scan.coverity.com/builds?project=behdad-harfbuzz
+ https://scan.coverity.com/builds?project=HarfBuzz
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
index c6d6e6dc5..3a95e9b64 100644
--- a/.github/workflows/linux-ci.yml
+++ b/.github/workflows/linux-ci.yml
@@ -3,18 +3,22 @@ name: linux-ci
on:
push:
branches: [ main ]
+ tags: ["*.*.*"]
pull_request:
branches: [ main ]
+permissions:
+ contents: read
+
jobs:
build:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: install dependencies
- run: sudo apt-get install pkg-config gcc gcovr gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev
- - run: sudo pip3 install fonttools meson==0.56.0
+ run: sudo apt-get update && sudo apt-get install pkg-config gcc gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev
+ - run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0
- name: run
run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Dragel_subproject=true -Doptimization=2
- name: ci
@@ -23,7 +27,7 @@ jobs:
- name: generate documentations
run: ninja -Cbuild harfbuzz-doc
- name: deploy documentations
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+ if: github.ref_type == 'tag'
run: .ci/deploy-docs.sh
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
@@ -48,6 +52,6 @@ jobs:
- name: cov
run: ninja -Cbuild coverage-xml
- - uses: codecov/codecov-action@v1
+ - uses: codecov/codecov-action@v3
with:
file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml
index 84e54df17..6a0b793f6 100644
--- a/.github/workflows/macos-ci.yml
+++ b/.github/workflows/macos-ci.yml
@@ -6,22 +6,19 @@ on:
pull_request:
branches: [ main ]
+permissions:
+ contents: read
+
jobs:
build:
- runs-on: macos-10.15
+ runs-on: macos-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: install dependencies
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config freetype glib cairo icu4c graphite2 gobject-introspection gtk-doc ninja gcovr
- - run: pip3 install meson fonttools --upgrade
+ run: HOMEBREW_NO_AUTO_UPDATE=1 brew install meson pkg-config freetype glib glib-utils cairo icu4c graphite2 gobject-introspection gtk-doc ninja
+ - run: pip3 install fonttools
- name: run
- run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Db_coverage=true -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2
+ run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2
- name: ci
run: meson test --print-errorlogs -Cbuild
-
- - name: cov
- run: ninja -Cbuild coverage-xml
- - uses: codecov/codecov-action@v1
- with:
- file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/msvc-ci.yml b/.github/workflows/msvc-ci.yml
index 7c9f5bc76..79be9f63b 100644
--- a/.github/workflows/msvc-ci.yml
+++ b/.github/workflows/msvc-ci.yml
@@ -6,16 +6,20 @@ on:
pull_request:
branches: [ main ]
+permissions:
+ contents: read
+
jobs:
msvc:
runs-on: ${{ matrix.os }}
strategy:
+ fail-fast: false
matrix:
- os: [windows-2016, windows-latest]
+ os: [windows-2019, windows-latest]
include:
- - name: msvc-2017-x86
- os: windows-2016
+ - name: msvc-2019-x86
+ os: windows-2019
ARCH: x86
- name: msvc-2019-amd64
os: windows-latest
@@ -23,13 +27,16 @@ jobs:
name: ${{ matrix.name }}
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: ilammy/msvc-dev-cmd@v1
with:
arch : ${{ matrix.ARCH }}
+ - name: Upgrade pip
+ run: |
+ python -m pip install -U pip
- name: Install Dependencies
run: |
pip install --upgrade meson ninja fonttools
@@ -39,7 +46,7 @@ jobs:
$env:path = ($env:path.Split(';') | Where-Object { $_ -ne 'C:\Strawberry\perl\bin' }) -join ';'
meson setup build `
- --wrap-mode=default `
+ --wrap-mode=forcefallback `
--buildtype=release `
-Dglib=enabled `
-Dfreetype=enabled `
diff --git a/.github/workflows/msys2-ci.yml b/.github/workflows/msys2-ci.yml
index b8b2fc390..d5bddb435 100644
--- a/.github/workflows/msys2-ci.yml
+++ b/.github/workflows/msys2-ci.yml
@@ -6,11 +6,15 @@ on:
pull_request:
branches: [ main ]
+permissions:
+ contents: read
+
jobs:
msys2:
runs-on: windows-latest
strategy:
+ fail-fast: false
matrix:
include:
- MSYSTEM: MINGW32
@@ -19,11 +23,16 @@ jobs:
MSYS2_ARCH: x86_64
name: ${{ matrix.MSYSTEM }}
+ env:
+ # XXX: For some reason enabling jit debugging "fixes" random python crashes
+ # see https://github.com/msys2/MINGW-packages/issues/11864
+ MSYS: "winjitdebug"
+
defaults:
run:
shell: msys2 {0}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.MSYSTEM }}
diff --git a/Android.bp b/Android.bp
index 57ae0b7c8..dd5f9e738 100644
--- a/Android.bp
+++ b/Android.bp
@@ -81,16 +81,54 @@ license {
name: "external_harfbuzz_ng_license",
visibility: [":__subpackages__"],
license_kinds: [
+ // "SPDX-license-Identifier-MIT-Modern-Variant",
"SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-ISC",
+ "SPDX-license-identifier-ISC", // src/hb-ucd.cc
"SPDX-license-identifier-MIT",
"SPDX-license-identifier-OFL", // by exception only
- "SPDX-license-identifier-WTFPL",
"legacy_unencumbered",
],
license_text: [
"COPYING",
"NOTICE",
+
+ "LICENSE_APACHE2.TXT",
+ "LICENSE_ISC.TXT",
+ "LICENSE_OFL.TXT",
+ "src/ms-use/COPYING", // For MIT license
+ "LICENSE_MIT_MODERN_VARIANT.TXT",
+ ],
+}
+
+cc_library {
+ name: "libharfbuzz_subset",
+ srcs: [
+ "src/hb-number.cc",
+ "src/hb-ot-cff1-table.cc",
+ "src/hb-ot-cff2-table.cc",
+ "src/hb-static.cc",
+ "src/hb-subset-cff-common.cc",
+ "src/hb-subset-cff1.cc",
+ "src/hb-subset-cff2.cc",
+ "src/hb-subset-input.cc",
+ "src/hb-subset-plan.cc",
+ "src/hb-subset-repacker.cc",
+ "src/hb-subset.cc",
+ "src/graph/gsubgpos-context.cc",
+ ],
+ shared_libs: [
+ "libharfbuzz_ng",
+ ],
+ export_include_dirs: ["src"],
+ cflags: [
+ "-DHAVE_PTHREAD",
+ "-DHB_NO_PRAGMA_GCC_DIAGNOSTIC",
+ "-DHAVE_OT",
+ "-DHAVE_ICU",
+ "-DHAVE_ICU_BUILTIN",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-missing-field-initializers",
],
}
@@ -107,37 +145,41 @@ cc_library {
"src/hb-aat-map.cc",
"src/hb-blob.cc",
"src/hb-buffer-serialize.cc",
+ "src/hb-buffer-verify.cc",
"src/hb-buffer.cc",
"src/hb-common.cc",
+ "src/hb-draw.cc",
"src/hb-face.cc",
"src/hb-fallback-shape.cc",
"src/hb-font.cc",
- "src/hb-icu.cc",
+ "src/hb-map.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
"src/hb-ot-cff2-table.cc",
+ "src/hb-ot-color.cc",
"src/hb-ot-face.cc",
"src/hb-ot-font.cc",
"src/hb-ot-layout.cc",
"src/hb-ot-map.cc",
"src/hb-ot-math.cc",
+ "src/hb-ot-meta.cc",
"src/hb-ot-metrics.cc",
"src/hb-ot-name.cc",
- "src/hb-ot-shape-complex-arabic.cc",
- "src/hb-ot-shape-complex-default.cc",
- "src/hb-ot-shape-complex-hangul.cc",
- "src/hb-ot-shape-complex-hebrew.cc",
- "src/hb-ot-shape-complex-indic-table.cc",
- "src/hb-ot-shape-complex-indic.cc",
- "src/hb-ot-shape-complex-khmer.cc",
- "src/hb-ot-shape-complex-myanmar.cc",
- "src/hb-ot-shape-complex-syllabic.cc",
- "src/hb-ot-shape-complex-thai.cc",
- "src/hb-ot-shape-complex-use.cc",
- "src/hb-ot-shape-complex-vowel-constraints.cc",
"src/hb-ot-shape-fallback.cc",
"src/hb-ot-shape-normalize.cc",
"src/hb-ot-shape.cc",
+ "src/hb-ot-shaper-arabic.cc",
+ "src/hb-ot-shaper-default.cc",
+ "src/hb-ot-shaper-hangul.cc",
+ "src/hb-ot-shaper-hebrew.cc",
+ "src/hb-ot-shaper-indic-table.cc",
+ "src/hb-ot-shaper-indic.cc",
+ "src/hb-ot-shaper-khmer.cc",
+ "src/hb-ot-shaper-myanmar.cc",
+ "src/hb-ot-shaper-syllabic.cc",
+ "src/hb-ot-shaper-thai.cc",
+ "src/hb-ot-shaper-use.cc",
+ "src/hb-ot-shaper-vowel-constraints.cc",
"src/hb-ot-tag.cc",
"src/hb-ot-var.cc",
"src/hb-set.cc",
@@ -145,15 +187,9 @@ cc_library {
"src/hb-shape.cc",
"src/hb-shaper.cc",
"src/hb-static.cc",
+ "src/hb-style.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",
- "src/hb-subset-cff-common.cc",
- "src/hb-subset-cff1.cc",
- "src/hb-subset-cff2.cc",
- "src/hb-subset-input.cc",
- "src/hb-subset-plan.cc",
- "src/hb-subset.cc",
- "src/hb-map.cc",
],
target: {
@@ -191,3 +227,197 @@ cc_library {
"-Wno-missing-field-initializers",
],
}
+
+/////////////////////////////////////////////////////////////////////
+// Following filegroups and licences are ones not used in Android.
+/////////////////////////////////////////////////////////////////////
+
+license {
+ name: "external_harfbuzz_license.unused.GPLv3",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-GPL-3.0-with-autoconf-exception",
+ ],
+ license_text: [
+ "LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.GPLv3",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.GPLv3"],
+ srcs: [
+ "m4/ax_check_link_flag.m4",
+ "m4/ax_pthread.m4",
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.GPLv2",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-GPL-2.0",
+ ],
+ license_text: [
+ "LICENSE_GPLv2.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.GPLv2",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.GPLv2"],
+ srcs: [
+ "test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf"
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.LGPL",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-LGPL-2.1",
+ ],
+ license_text: [
+ "LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.LGPL",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.LGPL"],
+ srcs: ["m4/ax_code_coverage.m4"],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.MIT",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-MIT",
+ ],
+ license_text: [
+ "src/ms-use/COPYING",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.MIT",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.MIT"],
+ srcs: [
+ "src/ms-use/*",
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.FSFAP",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-FSFAP",
+ ],
+ license_text: [
+ "LICENSE_FSFAP.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.FSFAP",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.FSFAP"],
+ srcs: [
+ "git.mk",
+ "m4/ax_cxx_compile_stdcxx.m4",
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.HPND-sell-variant",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ // "SPDX-license-identifier-HPND-sell-variant",
+ ],
+ license_text: [
+ "LICENSE_HPND_SELL_VARIANT.TXT"
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.HPND-sell-variant",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.HPND-sell-variant"],
+ srcs: [
+ "util/hb-fc-list.c",
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.Apache-2.0",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "LICENSE_APACHE2.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.Apache-2.0",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.Apache-2.0"],
+ srcs: [
+ "perf/fonts/Roboto-Regular.ttf"
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.OFL",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-OFL",
+ ],
+ license_text: [
+ "LICENSE_OFL.TXT",
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.OFL",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.OFL"],
+ srcs: [
+ "perf/fonts/Amiri-Regular.ttf",
+ "perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+ ],
+}
+
+license {
+ name: "external_harfbuzz_license.unused.tests",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ // "SPDX-license-Identifier-MIT-Modern-Variant",
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-MIT",
+ "SPDX-license-identifier-OFL", // by exception only
+ // Lots of font files used in tests directories are lack of license descriptions.
+ // The license of fuzzing payload is unknown.
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "LICENSE_OFL.TXT",
+ "LICENSE_APACHE2.TXT",
+ "LICENSE_MIT_MODERN_VARIANT.TXT",
+ "src/ms-use/COPYING", // For MIT license
+ ],
+}
+
+filegroup {
+ name: "external_harfbuzz.unused.tests",
+ visibility: ["//visibility:private"],
+ licenses: ["external_harfbuzz_license.unused.tests"],
+ srcs: [ "test/**/*" ],
+ path: "test"
+}
+
diff --git a/BUILD.md b/BUILD.md
index f64f8687d..8e822738c 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,27 +1,29 @@
-On Linux, install the development packages for FreeType,
-Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
+On Linux, install the development packages for FreeType, Cairo, and GLib. For
+example, on Ubuntu / Debian, you would do:
- sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
+$ sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
- sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-dev
+$ sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel
and on ArchLinux and Manjaro:
- sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
+$ sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
then use meson to build the project like `meson build && meson test -Cbuild`.
-On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` then use
-meson like above.
+On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson`
+then use meson like above.
-On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`)
-or gcc/clang is already on your path, and if you use something like `meson build --wrap-mode=default`
-it fetches and compiles most of the dependencies also.
+On Windows, meson can build the project like above if a working MSVC's cl.exe
+(`vcvarsall.bat`) or gcc/clang is already on your path, and if you use
+something like `meson build --wrap-mode=default` it fetches and compiles most
+of the dependencies also. It is recommended to install CMake either manually
+or via the Visual Studio installer when building with MSVC, using meson.
Our CI configurations is also a good source of learning how to build HarfBuzz.
-There is also amalgam source provided with HarfBuzz which reduces whole process of building
-HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is not guarantee provided
-with buildability and reliability of features you get.
+There is also amalgam source provided with HarfBuzz which reduces whole process
+of building HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is
+not guarantee provided with buildability and reliability of features you get.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 295cff8e3..97980ef59 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.12)
project(harfbuzz)
message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build systems to it, please consider using it as we might remove our cmake port soon.")
@@ -37,6 +37,10 @@ option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
+if (TARGET freetype)
+ set (HB_HAVE_FREETYPE ON)
+ add_definitions(-DHAVE_FREETYPE=1)
+endif ()
if (APPLE)
option(HB_HAVE_CORETEXT "Enable CoreText shaper backend on macOS" ON)
set (CMAKE_MACOSX_RPATH ON)
@@ -76,6 +80,7 @@ include (FindPythonInterp)
## Functions and headers
include (CheckFunctionExists)
include (CheckIncludeFile)
+include (CheckIncludeFiles)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
string(TOUPPER ${func_name} definition_to_add)
@@ -102,12 +107,17 @@ if (${HAVE_STDBOOL_H})
add_definitions(-DHAVE_STDBOOL_H)
endif ()
+# These will be used while making pkg-config .pc files
+set(PC_REQUIRES_PRIV "")
+set(PC_LIBS_PRIV "")
+
if (NOT MSVC)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (CMAKE_USE_PTHREADS_INIT)
add_definitions("-DHAVE_PTHREAD")
list(APPEND THIRD_PARTY_LIBS Threads::Threads)
+ list(APPEND PC_LIBS_PRIV -pthread)
endif ()
endif ()
@@ -184,7 +194,7 @@ set (project_headers ${HB_BASE_headers})
set (subset_project_headers ${HB_SUBSET_headers})
## Find and include needed header folders and libraries
-if (HB_HAVE_FREETYPE)
+if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
include (FindFreetype)
if (NOT FREETYPE_FOUND)
message(FATAL_ERROR "HB_HAVE_FREETYPE was set, but we failed to find it. Maybe add a CMAKE_PREFIX_PATH= to your Freetype2 install prefix")
@@ -203,6 +213,10 @@ if (HB_HAVE_FREETYPE)
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
endif ()
+if (HB_HAVE_FREETYPE)
+ list(APPEND PC_REQUIRES_PRIV "freetype2 >= 12.0.6")
+endif ()
+
if (HB_HAVE_GRAPHITE2)
add_definitions(-DHAVE_GRAPHITE2)
@@ -215,6 +229,8 @@ if (HB_HAVE_GRAPHITE2)
list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
+ list(APPEND PC_REQUIRES_PRIV "graphite2 >= 1.2.0")
+
mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
endif ()
@@ -235,6 +251,8 @@ if (HB_HAVE_GLIB)
list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
+ list(APPEND PC_REQUIRES_PRIV "glib-2.0 >= 2.19.1")
+
mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
endif ()
@@ -267,24 +285,28 @@ if (APPLE AND HB_HAVE_CORETEXT)
find_library(COREFOUNDATION CoreFoundation)
if (COREFOUNDATION)
list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
+ list(APPEND PC_LIBS_PRIV "-framework CoreFoundation")
endif ()
mark_as_advanced(COREFOUNDATION)
find_library(CORETEXT CoreText)
if (CORETEXT)
list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
+ list(APPEND PC_LIBS_PRIV "-framework CoreText")
endif ()
mark_as_advanced(CORETEXT)
find_library(COREGRAPHICS CoreGraphics)
if (COREGRAPHICS)
list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
+ list(APPEND PC_LIBS_PRIV "-framework CoreGraphics")
endif ()
mark_as_advanced(COREGRAPHICS)
else ()
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
if (APPLICATION_SERVICES_FRAMEWORK)
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
+ list(APPEND PC_LIBS_PRIV "-framework ApplicationServices")
endif ()
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
@@ -295,18 +317,27 @@ if (WIN32 AND HB_HAVE_GDI)
add_definitions(-DHAVE_GDI)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
list(APPEND THIRD_PARTY_LIBS gdi32)
+ list(APPEND PC_LIBS_PRIV -lgdi32)
endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
add_definitions(-DHAVE_UNISCRIBE)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
+ list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4)
endif ()
if (WIN32 AND HB_HAVE_DIRECTWRITE)
+ if (CMAKE_VERSION VERSION_GREATER 3.12)
+ check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H LANGUAGE CXX)
+ else ()
+ check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H)
+ endif ()
+ if (NOT HAVE_DWRITE_1_H)
+ message(FATAL_ERROR "DirectWrite was enabled explicitly, but required header is missing")
+ endif ()
add_definitions(-DHAVE_DIRECTWRITE)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
- list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
endif ()
if (HB_HAVE_GOBJECT)
@@ -421,6 +452,10 @@ target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
target_include_directories(harfbuzz PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
+if (HB_HAVE_FREETYPE AND TARGET freetype)
+ target_link_libraries(harfbuzz freetype)
+endif ()
+
## Define harfbuzz-icu library
if (HB_HAVE_ICU)
@@ -454,7 +489,9 @@ if (UNIX OR MINGW)
link_libraries(-Bsymbolic-functions)
endif ()
- if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # As of CMake 3.0.0, the compiler id for Apple-provided Clang is now "AppleClang";
+ # thus we use MATCHES instead of STREQUAL to include either regular Clang or AppleClang
+ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Make sure we don't link to libstdc++
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
@@ -683,6 +720,44 @@ if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
endif ()
endif ()
+# get these variables in the required format
+list(REMOVE_DUPLICATES PC_REQUIRES_PRIV)
+string(REPLACE ";" ", " PC_REQUIRES_PRIV "${PC_REQUIRES_PRIV}")
+list(REMOVE_DUPLICATES PC_LIBS_PRIV)
+string(REPLACE ";" " " PC_LIBS_PRIV "${PC_LIBS_PRIV}")
+
+# Macro to write pkg-config .pc configuration files
+macro ( make_pkgconfig_pc_file name )
+ file(READ "${PROJECT_SOURCE_DIR}/src/${name}.pc.in" FSTR)
+
+ string(REPLACE "%prefix%" "${CMAKE_INSTALL_PREFIX}" FSTR ${FSTR})
+ string(REPLACE "%exec_prefix%" "\${prefix}" FSTR ${FSTR})
+
+ if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
+ string(REPLACE "%includedir%" "${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
+ else ()
+ string(REPLACE "%includedir%" "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
+ endif ()
+
+ if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
+ string(REPLACE "%libdir%" "${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
+ else ()
+ string(REPLACE "%libdir%" "\${prefix}/${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
+ endif ()
+
+ string(REPLACE "%VERSION%" "${HB_VERSION}" FSTR ${FSTR})
+ string(REPLACE "%requires_private%" "${PC_REQUIRES_PRIV}" FSTR ${FSTR})
+ string(REPLACE "%libs_private%" "${PC_LIBS_PRIV}" FSTR ${FSTR})
+
+ file(WRITE "${PROJECT_BINARY_DIR}/${name}.pc" ${FSTR})
+
+ install(
+ FILES "${PROJECT_BINARY_DIR}/${name}.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
+ COMPONENT pkgconfig
+ )
+endmacro ( make_pkgconfig_pc_file )
+
if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS harfbuzz
EXPORT harfbuzzConfig
@@ -691,6 +766,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
+ make_pkgconfig_pc_file("harfbuzz")
install(EXPORT harfbuzzConfig
NAMESPACE harfbuzz::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
@@ -702,11 +778,13 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
+ make_pkgconfig_pc_file("harfbuzz-icu")
endif ()
if (HB_BUILD_SUBSET)
install(TARGETS harfbuzz-subset
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- )
+ )
+ make_pkgconfig_pc_file("harfbuzz-subset")
endif ()
if (HB_BUILD_UTILS)
if (WIN32 AND BUILD_SHARED_LIBS)
@@ -735,6 +813,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+ make_pkgconfig_pc_file("harfbuzz-gobject")
if (HB_HAVE_INTROSPECTION)
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
diff --git a/CONFIG.md b/CONFIG.md
index 2ca02935c..0faa359e6 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -100,13 +100,14 @@ This is very rarely what you need. Make sure you understand exactly what you
are doing.
Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the
-(unused) "fallback" shaper.
+(unused) "fallback" shaper. This is defined by the `HB_TINY` profile already
+(more below).
## Thread-safety
By default HarfBuzz builds as a thread-safe library. The exception is that
-the `HB_TINY` predefined configuring (more below) disables thread-safety.
+the `HB_TINY` predefined configuration (more below) disables thread-safety.
If you do *not* need thread-safety in the library (eg. you always call into
HarfBuzz from the same thread), you can disable thread-safety by defining
@@ -135,10 +136,17 @@ The pre-defined configurations are:
Most of the time, one of the pre-defined configuration is exactly what one needs.
Sometimes, however, the pre-defined configuration cuts out features that might
be desired in the library. Unfortunately there is no quick way to undo those
-configurations from the command-line. But one can add a header file called
-`config-override.h` to undefine certain `HB_NO_*` symbols as desired. Then
-define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
-overrides at the end.
+configurations from the command-line.
+
+However, configuration can still be overridden from a file. To do that, add your
+override instructions (mostly `undef` instructions) to a header file and define
+the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's
+name. HarfBuzz will then include that file at the appropriate place during
+configuration.
+
+Up until HarfBuzz 3.1.2 the the configuration override header file's name was
+fixed and called `config-override.h`, and was activated by defining the macro
+`HAVE_CONFIG_OVERRIDE_H`. That still works.
## Notes
@@ -147,4 +155,4 @@ Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
`HB_TINY` does *not* mean that the resulting library won't work with CFF fonts.
The library can shape valid CFF fonts just fine, with or without this option.
This option disables (among other things) the code to calculate glyph extents
-for CFF fonts.
+for CFF fonts, which many clients might not need.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..7e75ed05e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,4735 @@
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+-------------------------------------------------------------------
+
+Converted by Andrey V. Panov from TeX fonts. Some glyphs are copied from Blue Sky fonts released by AMS.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied together with this font package in OFL.txt,
+and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (C) 2011 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
+
+-------------------------------------------------------------------
+
+Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2012 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 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
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 Adobe Systems Incorporated. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+DejaVu changes are in public domain
+
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007, Denis Moyogo Jacquerye <moyogo@gmail.com>, with Reserved Font Name Molengo
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007, Denis Moyogo Jacquerye <moyogo@gmail.com>, with Reserved Font Name Molengo
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/ofl
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007-2008, The C&MA Guinea Fulbe Team;
+
+Copyright renewed 2011-2012, George W. Nuss (http://www.fulbefouta.com),
+with the Reserved Font Name "Fouta".
+
+Copyright (c) 2004-2020, SIL International (http://www.sil.org),
+with Reserved Font Names 'Andika' and 'SIL'.
+
+Copyright (c) 2014-2020, SIL International (http://www.sil.org/).
+with Reserved Font Names "Harmattan" and "SIL".
+
+Copyright (c) 2007-2008, The C&MA Guinea Fulbe Team;
+
+Copyright renewed 2011-2012, George W. Nuss (http://www.fulbefouta.com),
+with the Reserved Font Name "Fouta".
+
+Copyright (c) 2004-2020, SIL International (http://www.sil.org),
+with Reserved Font Names 'Andika' and 'SIL'.
+
+Copyright (c) 2014-2020, SIL International (http://www.sil.org/).
+with Reserved Font Names "Harmattan" and "SIL".
+
+----------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+----------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
+
+5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+Copyright (c) 2015 Paul Norman <penorman@mac.com>
+Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+
+Copying and distribution of this file, with or without modification, are
+permitted in any medium without royalty provided the copyright notice
+and this notice are preserved. This file is offered as-is, without any
+warranty.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <https://www.gnu.org/licenses/>.
+
+As a special exception, the respective Autoconf Macro's copyright owner
+gives unlimited permission to copy, distribute and modify the configure
+scripts that are the output of Autoconf when processing the Macro. You
+need not follow the terms of the GNU General Public License when using
+or distributing such scripts, even though portions of the text of the
+Macro appear in them. The GNU General Public License (GPL) does govern
+all other use of the material that constitutes the Autoconf Macro.
+
+This special exception to the GPL applies to versions of the Autoconf
+Macro released by the Autoconf Archive. When you make and distribute a
+modified version of the Autoconf Macro, you may extend this special
+exception to the GPL to apply to your modified version as well.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <https://www.gnu.org/licenses/>.
+
+As a special exception, the respective Autoconf Macro's copyright owner
+gives unlimited permission to copy, distribute and modify the configure
+scripts that are the output of Autoconf when processing the Macro. You
+need not follow the terms of the GNU General Public License when using
+or distributing such scripts, even though portions of the text of the
+Macro appear in them. The GNU General Public License (GPL) does govern
+all other use of the material that constitutes the Autoconf Macro.
+
+This special exception to the GPL applies to versions of the Autoconf
+Macro released by the Autoconf Archive. When you make and distribute a
+modified version of the Autoconf Macro, you may extend this special
+exception to the GPL to apply to your modified version as well.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009-2010 by Yoram Gnat (yoram.gnat@gmail.com)
+Distributed under the terms of GNU General Public License version 2(http://www.gnu.org/licenses/gpl.html).
+
+Hebrew OpenType Layout logic copyright (c) 2003 & 2007, Ralph Hancock & John Hudson. This layout logic for Biblical Hebrew is open source software under the MIT License; for details contact copyright holders at <license@tiro.com>.
+
+Latin glyphs and part of punctuation copyright 1990 as an unpublished work by Bitstream Inc.
+
+Hebrew glyphs, vowels, cantillation marks and implementation of above layout logic copyright (c)2009-2010 by Yoram Gnat (yoramg@shenkar.ac.il). Distributed under the terms of GNU General Public Licence version 2 (http://www.gnu.org/licenses/gpl.html)
+
+As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010-2017, Khaled Hosny <khaledhosny@eglug.org>.
+Portions copyright (c) 2010, Sebastian Kosch <sebastian@aldusleaf.org>.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 Hjort Nidudsson
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 Hjort Nidudsson
+
+SIL Open Font License
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012 Andhrapradesh Society for Knowledge Networks (fonts.siliconandhra.org). Copyright (c) 2011-2012, Sorkin Type Co (www.sorkintype.com) with Reserved Font Name 'Cantata'
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012 Andhrapradesh Society for Knowledge Networks (fonts.siliconandhra.org). Copyright (c) 2011-2012, Sorkin Type Co (www.sorkintype.com) with Reserved Font Name 'Cantata'
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012, 2016 Philip Withnall
+Copyright (c) 2012 Xan Lopez
+Copyright (c) 2012 Christian Persch
+Copyright (c) 2012 Paolo Borelli
+Copyright (c) 2012 Dan Winship
+Copyright (c) 2015 Bastien ROUCARIES
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at
+your option) any later version.
+
+This library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013, Danh Hong (khmertype.org)
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013, Danh Hong (khmertype.org)
+
+Licensed under the Apache License, Version 2.0
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+Copyright (c) 2015 by FontTools. No rights reserved.
+
+https://github.com/behdad/fonttools/blob/master/LICENSE.txt
+
+-------------------------------------------------------------------
+
+Copyright (c) 2015, Cadson Demak (info@cadsondemak.com)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2016, Igalia S.L. (http://igalia.com/)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2016, Igalia S.L. (http://igalia.com/)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2017, David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) 2017, David Corbett
+
+https://creativecommons.org/publicdomain/zero/1.0/legalcode
+
+-------------------------------------------------------------------
+
+Copyright (c) 2017-2019 by Amin Abedi (@aminabedi68)-www.opentypeshop.com and Copyright (c) 2019 by Amin Abedi (@aminabedi68)-www.fontamin.com,
+with Reserved Font Name Estedad.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+Copyright (c) 2017-2019 by Amin Abedi (@aminabedi68)-www.opentypeshop.com and Copyright (c) 2019 by Amin Abedi (@aminabedi68)-www.fontamin.com,
+with Reserved Font Name Estedad.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2018 David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) 2018,
+
+-------------------------------------------------------------------
+
+Copyright (c) 2018, David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) 2018, SIL International (http://scripts.sil.org), with Reserved Font Names 'Shimenkan', 'Sapushan', 'Salaowu', and 'Taogu'. Latin glyphs copyright (c) 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2019 David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) 2019 Unicode
+
+Licensed under the SIL Open Font License (OFL-1.1) with Reserved Font Names ‘Da Lekh’ and ‘ᨯᩣᩃᩮ᩠ᨡ’
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright (c) 2019, The Noto Project Authors (github. com/googlei18n/noto-fonts). Copyright (c) 2019, Inter IKEA Systems B.V. (www.ikea.com) with Reserved Font Name IKEA. IKEA is a registered trademark of Inter IKEA Systems B.V.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2019, The Noto Project Authors (github. com/googlei18n/noto-fonts). Copyright (c) 2019, Inter IKEA Systems B.V. (www.ikea.com) with Reserved Font Name IKEA. IKEA is a registered trademark of Inter IKEA Systems B.V.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright (c) 2020, Fredrick R. Brennan
+
+Apache 2 licensed, see distributed LICENSE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2020, Google
+
+-------------------------------------------------------------------
+
+Copyright (c) 2021, David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) 2022 David Corbett
+
+-------------------------------------------------------------------
+
+Copyright (c) Microsoft Corporation.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
+
+-------------------------------------------------------------------
+
+Copyright (c) Mihail Bayaryn, 2005. All rights reserved. Chandas font is released under GNU General Public License. Full license text is available at http://www.gnu.org/copyleft/gpl.html. Latin and Cyrillic glyphs were added from DejaVu font and modified according to GPL. Dharmo rakSati rakSitaH.
+
+-------------------------------------------------------------------
+
+Copyright 2000, 2002, 2006, 2011 Adobe Systems Incorporated. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2000-2016 Adobe Systems Incorporated. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use these files except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright 2000-2016 Adobe Systems Incorporated. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use these files except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright 2001-2021 The STIX Fonts Project Authors (https://github.com/stipub/stixfonts)
+
+-------------------------------------------------------------------
+
+Copyright 2001-2021 The STIX Fonts Project Authors (https://github.com/stipub/stixfonts)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2008 The Bungee Project Authors (david@djr.com)
+
+-------------------------------------------------------------------
+
+Copyright 2008 The Bungee Project Authors (david@djr.com)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2009, Red Hat, Inc.
+Copyright 2010,2011,2012,2013 Behdad Esfahbod
+Written by Behdad Esfahbod
+
+Copying and distribution of this file, with or without modification,
+is permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+
+The latest version of this file can be downloaded from:
+
+-------------------------------------------------------------------
+
+Copyright 2010-2020 The Amiri Project Authors (https://github.com/alif-type/amiri).
+
+-------------------------------------------------------------------
+
+Copyright 2010-2020 The Amiri Project Authors (https://github.com/alif-type/amiri).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2010-2021 The Amiri Project Authors (https://github.com/aliftype/amiri).
+
+-------------------------------------------------------------------
+
+Copyright 2011 Canonical Ltd. Licensed under the Ubuntu Font Licence 1.0
+
+-------------------------------------------------------------------
+
+Copyright 2011 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2011 Google Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0
+
+-------------------------------------------------------------------
+
+Copyright 2011 Google Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+Copyright 2011 Google Inc. All Rights Reserved.
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+Copyright 2011 The Comfortaa Project Authors (https://github.com/alexeiva/comfortaa), with Reserved Font Name "Comfortaa".
+
+-------------------------------------------------------------------
+
+Copyright 2011 The Comfortaa Project Authors (https://github.com/alexeiva/comfortaa), with Reserved Font Name "Comfortaa".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2011-12 Lohit Fonts Project contributors.
+<http://fedorahosted.org/lohit>
+Open type tables written by:
+Pravin Satpute <psatpute AT redhat DOT com>
+Sneha Kore <skore At redhat DOT com>
+Latin glyphs designed by:
+Eduardo Rodriguez Tunni <fontime AT gmail DOT com>
+
+ Licensed under the SIL Open Font License 1.1 (see file OFL.txt)
+
+-------------------------------------------------------------------
+
+Copyright 2013 Google Inc.
+
+-------------------------------------------------------------------
+
+Copyright 2013 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2013 Google Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+Copyright 2013 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2013 The Alegreya Sans Project Authors (https://github.com/huertatipografica/Alegreya-Sans)
+
+-------------------------------------------------------------------
+
+Copyright 2013 The Alegreya Sans Project Authors (https://github.com/huertatipografica/Alegreya-Sans)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2014 Adobe Systems Incorporated. All Rights Reserved. Noto is a trademark of Google Inc. and may be registered in certain jurisdictions.
+
+-------------------------------------------------------------------
+
+Copyright 2014 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2015 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2015 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2015 Google LLC. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2015-2021 Google LLC. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2016 Adobe (http://www.adobe.com/).
+
+-------------------------------------------------------------------
+
+Copyright 2016 Adobe (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2016 Adobe Systems Incorporated (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This Font Software is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2016 Adobe Systems Incorporated (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2016 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2016 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2016 Monotype Hong Kong Ltd. and Monotype Imaging Inc. All rights reserved.
+
+This font software is the property of Monotype Imaging Inc., one of its affiliated entities, or its licensors (collectively, Monotype) and its use by you is covered under the terms of a license agreement. You have obtained this font software either directly from Monotype or from the Unicode Consortium. Monotype has granted the Consortium and recipients of the this font distributed by the Consortium, permission, free of charge, to use, copy modify, publish, distribute, sublicense, and/or sell copies of the font, and to permit persons to whom the font is distributed to do so. In addition, Monotype grants to the Consortium the worldwide, nonexclusive, royalty-free, paid-up, and irrevocable rights under Monotype's copyright rights to reproduce, publicly display, publicly perform, prepare derivative works of, and distribute copies of the font, and the right to sublicense others who legally receive copies of the font. You can learn more about Monotype here: www.monotype.com
+
+http://www.monotype.com
+
+-------------------------------------------------------------------
+
+Copyright 2016 The M+ Project Authors.
+
+-------------------------------------------------------------------
+
+Copyright 2016 The M+ Project Authors.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2016 Unicode Inc. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the “License”);
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an “AS IS” BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright 2017 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2017 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2017 The Roboto Flex Project Authors (https://github.com/TypeNetwork/Roboto-Flex)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2017 The Spectral Project Authors (http://github.com/productiontype/spectral)
+
+-------------------------------------------------------------------
+
+Copyright 2017 The Spectral Project Authors (http://github.com/productiontype/spectral)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2017 by Jens Kutilek
+
+-------------------------------------------------------------------
+
+Copyright 2017 by Unicode Inc.
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright 2017-2022 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2017-2022 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2018 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2018 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2018-2022 Google Inc. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2019 Khaled Hosny
+
+-------------------------------------------------------------------
+
+Copyright 2019 The Cantarell Project Authors (https://gitlab.gnome.org/GNOME/cantarell-fonts)
+
+-------------------------------------------------------------------
+
+Copyright 2019-2021 Google LLC. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2019-2022 Google LLC. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright 2020 The Fraunces Project Authors (github.com/undercasetype/Fraunces)
+
+-------------------------------------------------------------------
+
+Copyright 2020 The Fraunces Project Authors (github.com/undercasetype/Fraunces)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2021 Red Hat, 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.
+
+Author(s): Matthias Clasen
+
+-------------------------------------------------------------------
+
+Copyright 2021 The M+ FONTS Project Authors (https://github.com/coz-m/MPLUS_FONTS)
+
+-------------------------------------------------------------------
+
+Copyright 2021 The M+ FONTS Project Authors (https://github.com/coz-m/MPLUS_FONTS)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2021 The Qahiri Project Authors (github.com/aliftype/qahiri).
+
+-------------------------------------------------------------------
+
+Copyright 2021 The Qahiri Project Authors (github.com/aliftype/qahiri).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
+
+https://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright 2021 The Raqq Project Authors (github.com/aliftype/raqq)
+
+-------------------------------------------------------------------
+
+Copyright 2022 David Corbett.
+
+-------------------------------------------------------------------
+
+Copyright © 1998-2004 David Turner and Werner Lemberg
+Copyright © 2004,2007,2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 1998-2004 David Turner and Werner Lemberg
+Copyright © 2004,2007,2009,2010 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 1998-2004 David Turner and Werner Lemberg
+Copyright © 2006 Behdad Esfahbod
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2012,2013 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2002 Keith Packard
+Copyright © 2014 Google, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of the author(s) not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. The authors make no
+representations about the suitability of this software for any purpose. It
+is provided "as is" without express or implied warranty.
+
+THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007 Chris Wilson
+Copyright © 2009,2010 Red Hat, Inc.
+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.
+
+Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, 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.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod, Garret Rieger
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2012,2013 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2012,2013 Google, Inc.
+Copyright © 2019, Facebook 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+Facebook Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009 Red Hat, Inc.
+Copyright © 2018,2019,2020 Ebrahim Byagowi
+Copyright © 2018 Khaled Hosny
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009,2010 Red Hat, Inc.
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009,2010 Red Hat, Inc.
+Copyright © 2010,2012,2013 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009,2010 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009,2010 Red Hat, Inc.
+Copyright © 2012,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2007,2008,2009,2010 Red Hat, Inc.
+Copyright © 2012,2018 Google, Inc.
+Copyright © 2019 Facebook, 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+Facebook Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, 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.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2009 Keith Stribley
+Copyright © 2011 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2009 Keith Stribley
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2011 Codethink Limited
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Codethink Author(s): Ryan Lortie
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2011 Codethink Limited
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Codethink Author(s): Ryan Lortie
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2011 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2011 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod, Roozbeh Pournader
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+Copyright © 2018 Ebrahim Byagowi
+
+ 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.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009,2010 Red Hat, Inc.
+Copyright © 2010,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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009,2010 Red Hat, Inc.
+Copyright © 2010,2011,2012,2013 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009,2010 Red Hat, Inc.
+Copyright © 2010,2011,2013 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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2009,2010 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2010 Behdad Esfahbod
+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
+
+-------------------------------------------------------------------
+
+Copyright © 2010 Behdad Esfahbod
+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): Garret Rieger, Rod Sheeter
+
+-------------------------------------------------------------------
+
+Copyright © 2010 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
+
+-------------------------------------------------------------------
+
+Copyright © 2010 Red Hat, Inc.
+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.
+
+Red Hat Author(s): Behdad Esfahbod
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2010 NHN Corporation. All rights reserved. Font designed by FONTRIX.
+
+-------------------------------------------------------------------
+
+Copyright © 2010,2011 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
+
+-------------------------------------------------------------------
+
+Copyright © 2010,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
+
+-------------------------------------------------------------------
+
+Copyright © 2010,2011,2013 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
+
+-------------------------------------------------------------------
+
+Copyright © 2010,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
+
+-------------------------------------------------------------------
+
+Copyright © 2011 Codethink Limited
+Copyright © 2011 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.
+
+Codethink Author(s): Ryan Lortie
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2011 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
+
+-------------------------------------------------------------------
+
+Copyright © 2011 Google, Inc.
+Copyright © 2022 Behdad Esfahbod
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2011 Martin Hosken
+Copyright © 2011 SIL International
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2011 Martin Hosken
+Copyright © 2011 SIL International
+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
+
+-------------------------------------------------------------------
+
+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
+
+-------------------------------------------------------------------
+
+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, Roderick Sheeter
+
+-------------------------------------------------------------------
+
+Copyright © 2011,2012 Google, Inc.
+Copyright © 2018 Ebrahim Byagowi
+
+ 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
+
+-------------------------------------------------------------------
+
+Copyright © 2011,2012,2013 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
+
+-------------------------------------------------------------------
+
+Copyright © 2011,2012,2013 Google, Inc.
+Copyright © 2021 Khaled Hosny
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2011,2012,2014 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
+
+-------------------------------------------------------------------
+
+Copyright © 2011,2014 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, Roozbeh Pournader
+
+-------------------------------------------------------------------
+
+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
+
+-------------------------------------------------------------------
+
+Copyright © 2012 Mozilla Foundation.
+
+ 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
+
+-------------------------------------------------------------------
+
+Copyright © 2012,2013 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
+
+-------------------------------------------------------------------
+
+Copyright © 2012,2013 Mozilla Foundation.
+Copyright © 2012,2013 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
+
+-------------------------------------------------------------------
+
+Copyright © 2012,2017 Google, Inc.
+Copyright © 2021 Behdad Esfahbod
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2012,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
+
+-------------------------------------------------------------------
+
+Copyright © 2013 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
+
+-------------------------------------------------------------------
+
+Copyright © 2013 Red Hat, 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.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2013, 2015 Adobe Systems Incorporated (http://www.adobe.com/).
+
+-------------------------------------------------------------------
+
+Copyright © 2013, 2015 Adobe Systems Incorporated (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2014 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
+
+-------------------------------------------------------------------
+
+Copyright © 2014 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, Roozbeh Pournader
+
+-------------------------------------------------------------------
+
+Copyright © 2014 Adobe Systems Incorporated. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+Copyright © 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'.
+
+-------------------------------------------------------------------
+
+Copyright © 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/).
+
+-------------------------------------------------------------------
+
+Copyright © 2014-2016 Adobe Systems Incorporated (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2015 Google, Inc.
+Copyright © 2019 Adobe Inc.
+Copyright © 2019 Ebrahim Byagowi
+
+ 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, Garret Rieger, Roderick Sheeter
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+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
+
+-------------------------------------------------------------------
+
+Copyright © 2015 Adobe Systems Incorporated (http://www.adobe.com/).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2015-2017 The Mada Project Authors, with Reserved Font Name "Source". Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2015-2019 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2015-2021 The Mada Project Authors, with Reserved Font Name “Source”.
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
+Copyright © 2018 Google, Inc.
+Copyright © 2018-2019 Ebrahim Byagowi
+
+ 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
+
+-------------------------------------------------------------------
+
+Copyright © 2016 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
+
+-------------------------------------------------------------------
+
+Copyright © 2016 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): Seigo Nonaka, Calder Kitagawa
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Google, Inc.
+Copyright © 2018 Ebrahim Byagowi
+
+ 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): Sascha Brawer
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Google, Inc.
+Copyright © 2018 Ebrahim Byagowi
+
+ 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): Sascha Brawer, Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Google, Inc.
+Copyright © 2018 Khaled Hosny
+Copyright © 2018 Ebrahim Byagowi
+
+ 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): Sascha Brawer, Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Igalia S.L.
+
+ 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.
+
+Igalia Author(s): Frédéric Wang
+
+-------------------------------------------------------------------
+
+Copyright © 2016 Unicode, Inc.
+
+-------------------------------------------------------------------
+
+Copyright © 2016 by Sascha Brawer. No rights reserved.
+
+-------------------------------------------------------------------
+
+Copyright © 2016 by Unicode Inc.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2016 by Unicode Inc.
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright © 2016 by Unicode, Inc.
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright © 2017 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
+
+-------------------------------------------------------------------
+
+Copyright © 2017 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.
+
+Red Hat Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2017 Google, Inc.
+Copyright © 2018 Ebrahim Byagowi
+
+ 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
+
+-------------------------------------------------------------------
+
+Copyright © 2017 Google, Inc.
+Copyright © 2019 Facebook, 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
+Facebook Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2017 by Unicode, Inc.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2017 by Unicode, Inc.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL. This Font Software is distributed on an ‘AS IS’ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2017 by Unicode, Inc.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+Copyright © 2017,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
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Ebrahim Byagowi
+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
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Ebrahim Byagowi
+Copyright © 2020 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Ebrahim Byagowi
+Copyright © 2020 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): Calder Kitagawa
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Ebrahim Byagowi.
+
+ 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.
+
+-------------------------------------------------------------------
+
+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
+
+-------------------------------------------------------------------
+
+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): Garret Rieger
+
+-------------------------------------------------------------------
+
+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): Garret Rieger, Rod Sheeter, Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+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): Garret Rieger, Roderick Sheeter
+
+-------------------------------------------------------------------
+
+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): Rod Sheeter
+
+-------------------------------------------------------------------
+
+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): Roderick Sheeter
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Google, Inc.
+Copyright © 2019 Facebook, 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
+Facebook Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Adobe 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.
+
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Unicode, Inc.
+
+-------------------------------------------------------------------
+
+Copyright © 2018 Unicode, Inc.
+
+This Font Software is licensed under the SIL Open Font License Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright © 2018-2019 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Adobe Inc.
+Copyright © 2019 Ebrahim Byagowi
+
+ 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.
+
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Adobe, 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.
+
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Facebook, 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.
+
+Facebook Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+Copyright © 2019 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
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Adobe 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.
+
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+Copyright © 2019 Unicode, Inc.
+
+This Font Software is licensed under the SIL Open Font License Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright © 2019 by Unicode, Inc.
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright © 2019-2020 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2020 Ebrahim Byagowi
+
+ 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2020 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): Calder Kitagawa
+
+-------------------------------------------------------------------
+
+Copyright © 2020 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
+
+-------------------------------------------------------------------
+
+Copyright © 2020 Adobe 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.
+
+Adobe Author(s): Michiharu Ariza
+
+-------------------------------------------------------------------
+
+Copyright © 2021 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2021 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2021 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.
+
+-------------------------------------------------------------------
+
+Copyright © 2021 Khaled Hosny
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright © 2022 Behdad Esfahbod
+
+ This is part of HarfBuzz, a text shaping library.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+Google Author(s): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+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): Behdad Esfahbod
+
+-------------------------------------------------------------------
+
+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
+
+-------------------------------------------------------------------
+
+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.
+
+-------------------------------------------------------------------
+
+Copyright © 2022 Red Hat, 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.
+
+-------------------------------------------------------------------
+
+Copyright ©1993–2016 by The Font Bureau, Inc. with Reserved Font Name “Zycon”
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright ©2016 by Unicode Inc.
+
+This Font Software is licensed under the SIL Open Font License Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Copyright ©2017 by Unicode Inc.
+
+This Font Software is licensed under the SIL Open Font License Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
+
+https://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+Digitized data copyright (c) 2010-2012 Google Corporation.
+
+-------------------------------------------------------------------
+
+Digitized data copyright (c) 2010-2012 Google Corporation.
+
+Licensed under the Apache License, Version 2.0
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+Digitized data copyright © 2010-2011, Google Corporation.
+
+-------------------------------------------------------------------
+
+Digitized data copyright © 2010-2011, Google Corporation.
+
+Licensed under the Apache License, Version 2.0
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+-------------------------------------------------------------------
+
+HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
+For parts of HarfBuzz that are licensed under different licenses see individual
+files names COPYING in subdirectories where applicable.
+
+Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
+Copyright © 2018,2019,2020 Ebrahim Byagowi
+Copyright © 2019,2020 Facebook, Inc.
+Copyright © 2012 Mozilla Foundation
+Copyright © 2011 Codethink Limited
+Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
+Copyright © 2009 Keith Stribley
+Copyright © 2009 Martin Hosken and SIL International
+Copyright © 2007 Chris Wilson
+Copyright © 2005,2006,2020,2021 Behdad Esfahbod
+Copyright © 2005 David Turner
+Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
+Copyright © 1998-2004 David Turner and Werner Lemberg
+
+For full copyright notices consult the individual files in the package.
+
+
+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.
+
+-------------------------------------------------------------------
+
+Jellee is a trademark of Alfredo Marco Pradil
+
+Copyright (c) 2016, Alfredo Marco Pradil,
+with Reserved Font Name Jellee Roman.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+The digitally signed machine readable Typeface(Font) licensed to you is copyrighted ©, (2010), King Fahd Glorious Quran Printing Complex.
+ISBN: 978-603-8010-15-0, Accession No. 1430/7278
+All rights reserved. This Font is the property of King Fahd Glorious Quran Printing Complex, and may not be reproduced, modified without the express written approval of King Fahd Glorious Quran Printing Complex.
+
+-------------------------------------------------------------------
+
+© 2005 Zawgyi.net & Alpha Mandalay. All rights reserved.
+Tahoma is a trademark and copyrighted property of Microsoft Corp.
+Myanmar glyphs are copyrighted by Zawgyi.net & Alpha Mandalay.
+
+-------------------------------------------------------------------
+
+© 2010 - 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+-------------------------------------------------------------------
+
+© 2010 - 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL. This Font Software is distributed on an ‘AS IS’ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+© 2010 - 2018 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+-------------------------------------------------------------------
+
+© 2010 - 2018 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL. This Font Software is distributed on an ‘AS IS’ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+© 2013 Microsoft Corporation. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+© 2014 - 2017 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+-------------------------------------------------------------------
+
+© 2014 - 2017 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL. This Font Software is distributed on an ‘AS IS’ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+
+http://scripts.sil.org/OFL
+
+-------------------------------------------------------------------
+
+© 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+http://opensource.org/licenses/OFL-1.1
+
+-------------------------------------------------------------------
+
+© 2020 Microsoft Corporation. All Rights Reserved.
+
+-------------------------------------------------------------------
+
+©1992, 2017 Thomas A. Rickner.
+
+https://github.com/TrueTyper/BuffaloGals/blob/master/LICENSE.txt
+
+-------------------------------------------------------------------
+
diff --git a/LICENSE_APACHE2.TXT b/LICENSE_APACHE2.TXT
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/LICENSE_APACHE2.TXT
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/LICENSE_FSFAP.TXT b/LICENSE_FSFAP.TXT
new file mode 100644
index 000000000..662cfe1db
--- /dev/null
+++ b/LICENSE_FSFAP.TXT
@@ -0,0 +1,4 @@
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without any warranty.
diff --git a/LICENSE_GPLv2.TXT b/LICENSE_GPLv2.TXT
new file mode 100644
index 000000000..a47ada128
--- /dev/null
+++ b/LICENSE_GPLv2.TXT
@@ -0,0 +1,125 @@
+GNU GENERAL PUBLIC LICENSE
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+Preamble
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+How to Apply These Terms to Your New Programs
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy name of author
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) year name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.
diff --git a/LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT b/LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT
new file mode 100644
index 000000000..ddd4e8f2a
--- /dev/null
+++ b/LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT
@@ -0,0 +1,307 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+Autoconf Exception
+
+As a special exception, the Free Software Foundation gives unlimited
+permission to copy, distribute and modify the configure scripts that are the
+output of Autoconf. You need not follow the terms of the GNU General Public
+License when using or distributing such scripts, even though portions of the
+text of Autoconf appear in them. The GNU General Public License (GPL) does
+govern all other use of the material that constitutes the Autoconf program.
+
+Certain portions of the Autoconf source text are designed to be copied (in
+certain cases, depending on the input) into the output of Autoconf. We call
+these the "data" portions. The rest of the Autoconf source text consists of
+comments plus executable code that decides which of the data portions to
+output in any given case. We call these comments and executable code the "non-
+data" portions. Autoconf never copies any of the non-data portions into its
+output.
+
+This special exception to the GPL applies to versions of Autoconf released by
+the Free Software Foundation. When you make and distribute a modified version
+of Autoconf, you may extend this special exception to the GPL to apply to your
+modified version as well, *unless* your modified version has the potential to
+copy into its output some of the text that was the non-data portion of the
+version that you started with. (In other words, unless your change moves or
+copies text from the non-data portions to the data portions.) If your
+modification has such potential, you must delete any notice of this special
+exception to the GPL from your modified version.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT b/LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT
new file mode 100644
index 000000000..b37355ee4
--- /dev/null
+++ b/LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT
@@ -0,0 +1,663 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+AUTOCONF CONFIGURE SCRIPT EXCEPTION
+
+Version 3.0, 18 August 2009
+
+Copyright © 2009 Free Software Foundation, Inc. <http://fsf.org/>
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+This Exception is an additional permission under section 7 of the GNU General
+Public License, version 3 ("GPLv3"). It applies to a given file that bears a
+notice placed by the copyright holder of the file stating that the file is
+governed by GPLv3 along with this Exception.
+
+The purpose of this Exception is to allow distribution of Autoconf&apos;s
+typical output under terms of the recipient&apos;s choice (including
+proprietary).
+
+0. Definitions.
+"Covered Code" is the source or object code of a version of Autoconf that is a
+covered work under this License.
+
+"Normally Copied Code" for a version of Autoconf means all parts of its
+Covered Code which that version can copy from its code (i.e., not from its
+input file) into its minimally verbose, non-debugging and non-tracing output.
+
+"Ineligible Code" is Covered Code that is not Normally Copied Code.
+
+1. Grant of Additional Permission.
+You have permission to propagate output of Autoconf, even if such propagation
+would otherwise violate the terms of GPLv3. However, if by modifying Autoconf
+you cause any Ineligible Code of the version you received to become Normally
+Copied Code of your modified version, then you void this Exception for the
+resulting covered work. If you convey that resulting covered work, you must
+remove this Exception in accordance with the second paragraph of Section 7 of
+GPLv3.
+
+2. No Weakening of Autoconf Copyleft.
+The availability of this Exception does not imply any general presumption that
+third-party software is unaffected by the copyleft requirements of the license
+of Autoconf.
diff --git a/LICENSE_HPND_SELL_VARIANT.TXT b/LICENSE_HPND_SELL_VARIANT.TXT
new file mode 100644
index 000000000..37327c81e
--- /dev/null
+++ b/LICENSE_HPND_SELL_VARIANT.TXT
@@ -0,0 +1,17 @@
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of the author(s) not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. The authors make no
+representations about the suitability of this software for any purpose. It
+is provided ""as is"" without express or implied warranty.
+
+THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/LICENSE_ISC.TXT b/LICENSE_ISC.TXT
new file mode 100644
index 000000000..34a6a760d
--- /dev/null
+++ b/LICENSE_ISC.TXT
@@ -0,0 +1,11 @@
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
diff --git a/LICENSE_MIT_MODERN_VARIANT.TXT b/LICENSE_MIT_MODERN_VARIANT.TXT
new file mode 100644
index 000000000..911076af2
--- /dev/null
+++ b/LICENSE_MIT_MODERN_VARIANT.TXT
@@ -0,0 +1,15 @@
+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.
diff --git a/LICENSE_OFL.TXT b/LICENSE_OFL.TXT
new file mode 100644
index 000000000..6f0eea4c6
--- /dev/null
+++ b/LICENSE_OFL.TXT
@@ -0,0 +1,85 @@
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+---------------------------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+---------------------------------------------------------------------------
+
+PREAMBLE
+
+The goals of the Open Font License (OFL) are to stimulate worldwide development
+of collaborative font projects, to support the font creation efforts of academic
+and linguistic communities, and to provide a free and open framework in which
+fonts may be shared and improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and redistributed
+freely as long as they are not sold by themselves. The fonts, including any
+derivative works, can be bundled, embedded, redistributed and/or sold with any
+software provided that any reserved names are not used by derivative works. The
+fonts and derivatives, however, cannot be released under any other type of license.
+The requirement for fonts to remain under this license does not apply to any
+document created using the fonts or their derivatives.
+
+DEFINITIONS
+
+"Font Software" refers to the set of files released by the Copyright Holder(s) under
+this license and clearly marked as such. This may include source files, build
+scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the copyright
+statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting, or
+substituting -- in part or in whole -- any of the components of the Original Version,
+by changing formats or by porting the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical writer or other
+person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of the
+Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell
+modified and unmodified copies of the Font Software, subject to the following
+conditions:
+
+1) Neither the Font Software nor any of its individual components, in Original or
+Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled, redistributed
+and/or sold with any software, provided that each copy contains the above copyright
+notice and this license. These can be included either as stand-alone text files,
+human-readable headers or in the appropriate machine-readable metadata fields within
+text or binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless
+explicit written permission is granted by the corresponding Copyright Holder. This
+restriction only applies to the primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall
+not be used to promote, endorse or advertise any Modified Version, except to
+acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with
+their explicit written permission.
+
+5) The Font Software, modified or unmodified, in part or in whole, must be distributed
+entirely under this license, and must not be distributed under any other license. The
+requirement for fonts to remain under this license does not apply to any document
+created using the Font Software.
+
+TERMINATION
+
+This license becomes null and void if any of the above conditions are not met.
+
+DISCLAIMER
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER
+RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
+INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/METADATA b/METADATA
index 2407f79be..979468117 100644
--- a/METADATA
+++ b/METADATA
@@ -1,14 +1,31 @@
-# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
-# CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
-# DEPENDING ON IT IN YOUR PROJECT. ***
+# THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+# CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+# DEPENDING ON IT IN YOUR PROJECT.
+
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update harfbuzz_ng
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
+name: "harfbuzz_ng"
+description: "HarfBuzz is a text shaping engine."
third_party {
+ url {
+ type: GIT
+ value: "https://github.com/harfbuzz/harfbuzz"
+ }
+ version: "6.0.0"
+ license_type: BY_EXCEPTION_ONLY
license_note: "would be NOTICE save for GPL in:\n"
- " m4/ax_code_coverage.m4\n"
+ " m4/ax_code_coverage.m4\n"
" and RESTRICTED save for OFL in:\n"
- " test/shaping/data/in-house/COPYING\n"
- " test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528\n"
+ " test/shaping/data/in-house/COPYING\n"
+ " test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528\n"
" Also take care when vendoring in not to import content like the\n"
" culp/ligatures font with CC-BY-NC-SA licensing. Google does not want to\n"
" host CC-BY-NC* content.\n"
- license_type: BY_EXCEPTION_ONLY
+ last_upgrade_date {
+ year: 2023
+ month: 2
+ day: 15
+ }
}
diff --git a/Makefile.am b/Makefile.am
index 3055e5a77..c14b4b7c2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,7 @@ NULL =
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = src util test docs
+SUBDIRS = src util test perf docs
EXTRA_DIST = \
autogen.sh \
@@ -25,20 +25,6 @@ EXTRA_DIST = \
subprojects/google-benchmark.wrap \
subprojects/ragel.wrap \
subprojects/packagefiles/ragel/meson.build \
- subprojects/ttf-parser.wrap \
- perf/meson.build \
- perf/perf-draw.hh \
- perf/perf-extents.hh \
- perf/perf-shaping.hh \
- perf/perf.cc \
- perf/fonts/Amiri-Regular.ttf \
- perf/fonts/NotoNastaliqUrdu-Regular.ttf \
- perf/fonts/NotoSansDevanagari-Regular.ttf \
- perf/fonts/Roboto-Regular.ttf \
- perf/texts/en-thelittleprince.txt \
- perf/texts/en-words.txt \
- perf/texts/fa-monologue.txt \
- perf/texts/fa-thelittleprince.txt \
mingw-configure.sh \
$(NULL)
diff --git a/NEWS b/NEWS
index da7d8db1d..73dcef083 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,484 @@
+Overview of changes leading to 6.0.0
+Friday, December 16, 2022
+====================================
+- A new API have been added to pre-process the face and speed up future
+ subsetting operations on that face. Provides up to a 95% reduction in
+ subsetting times when the same face is subset more than once.
+
+ For more details and benchmarks, see:
+ https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md
+
+ (Garret Rieger, Behdad Esfahbod)
+
+- Shaping have been speedup by skipping entire lookups when the buffer contents
+ don't intersect with the lookup. Shows up to a 10% speedup in shaping some
+ fonts. (Behdad Esfahbod)
+
+- A new experimental feature, “Variable Composites” (enabled by passing
+ -Dexperimental_api=true to meson), is also featured in this release.
+ This technology enables drastic compression of fonts in the Chinese,
+ Japanese, Korean, and other writing systems, by reusing the OpenType Font
+ Variations technology for encoding “smart components” into the font.
+
+ The specification for these extensions to the font format can be found in:
+ https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md
+
+ A test variable-font with ~7160 Hangul syllables derived from the
+ NotoSerifKR-VF font has been built, with existing OpenType technology, as
+ well as with the new Variable Composites (VarComposites) technology. The
+ VarComposites font is over 90% smaller than the OpenType version of the font!
+ Both fonts can be obtained from the “smarties” repository:
+ https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif
+
+ When building HarfBuzz with experimental features enabled, you can test
+ the “smarties” font with a sample character like this:
+
+ $ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700
+
+ (Behdad Esfahbod)
+
+- The HarfBuzz subsetter can now drop axes by pinning them to specific values
+ (also referred to as instancing). There are a couple of restrictions
+ currently:
+
+ - Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet
+ supported.
+ - Only supports the case where all axes in a font are pinned.
+
+ (Garret Rieger, Qunxin Liu)
+
+- Miscellaneous fixes and improvements.
+
+ (Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret
+ Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg,
+ Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik)
+
+
+- New API
++hb_subset_input_pin_axis_location()
++hb_subset_input_pin_axis_to_default()
++hb_subset_preprocess()
+
+
+Overview of changes leading to 5.3.1
+Wednesday, October 19, 2022
+====================================
+- Subsetter repacker fixes. (Garret Rieger)
+- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
+- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
+
+
+Overview of changes leading to 5.3.0
+Saturday, October 8, 2022
+"Women, Life, Freedom" #MahsaAmini
+====================================
+- Don’t add glyphs from dropped MATH or COLR tables to the subset glyphs.
+ (Khaled Hosny)
+- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
+- Update USE data files to latest version. (David Corbett)
+- Check “CBDT” extents first before outline tables, to help with fonts that
+ also include an empty “glyf” table. (Khaled Hosny)
+- More work towards variable font instancing in the subsetter. (Qunxin Liu)
+- Subsetter repacker improvements. (Garret Rieger)
+- New API:
++hb_ot_layout_lookup_get_optical_bound()
++hb_face_builder_sort_tables()
+
+
+Overview of changes leading to 5.2.0
+Saturday, September 17, 2022
+====================================
+- Fix regressions in hb-ft font functions for FT_Face’s with transformation
+ matrix. (Behdad Esfahbod)
+- The experimental hb-repacker API now supports splitting several GPOS subtable
+ types when needed. (Garret Rieger)
+- The HarfBuzz extensions to OpenType font format are now opt-in behind
+ build-time flags. (Behdad Esfahbod)
+- The experimental hb-subset variable fonts instantiation API can now
+ instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
+- Unicode 15 support. (David Corbett)
+- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
+- The hb-view command line tool now detects WezTerm inline images support.
+ (Wez Furlong)
+- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
+
+- New API:
++HB_SCRIPT_KAWI
++HB_SCRIPT_NAG_MUNDARI
+
+
+Overview of changes leading to 5.1.0
+Sunday, July 31, 2022
+====================================
+- More extensive buffer tracing messages. (Behdad Esfahbod)
+- Fix hb-ft regression in bitmap fonts rendering. (Behdad Esfahbod)
+- Support extension promotion of lookups in hb-subset-repacker. (Garret Rieger)
+- A new HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL for scripts that use elongation
+ (e.g. Arabic) to signify where it is safe to insert tatweel glyph without
+ interrupting shaping. (Behdad Esfahbod)
+- Add “--safe-to-insert-tatweel” to “hb-shape” tool. (Behdad Esfahbod)
+
+- New API
++HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
++HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL
+
+
+Overview of changes leading to 5.0.1
+Saturday, July 23, 2022
+====================================
+- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
+
+
+Overview of changes leading to 5.0.0
+Saturday, July 23, 2022
+====================================
+- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
+ tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
+ extend OpenType in a backward-compatible way.
+ (Behdad Esfahbod, Garret Rieger)
+- Complete support for more than 65535 glyphs in “glyf” table that started in
+ 4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
+- Support version 2 of “avar” table. Part of boring-expansion-spec.
+ (Behdad Esfahbod)
+- Fix mark attachment on multiple substitutions in some cases.
+ (Behdad Esfahbod)
+- Fix application of “calt”, “rclt”, and “ccmp” features to better match
+ Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
+- Improvement to interaction between multiple cursive attachments.
+ (Behdad Esfahbod)
+- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
+- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
+- Fix variation of “VORG” table. (Behdad Esfahbod)
+- Support for specific script tags to be retained in the subsetter, and add
+ “--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
+- Accept space as delimiter for --features/--variations in command line tools.
+- Improve subsetting of “COLR” table. (Qunxin Liu)
+- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
+- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
+ (Behdad Esfahbod)
+- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
+- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
+- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
+- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
+- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
+ (Luca Bacci)
+- Provide a single-file harfbuzz-subset.cc file for easier alternate building
+ of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
+
+- New API
++HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
++hb_language_matches()
+
+
+Overview of changes leading to 4.4.1
+Wednesday, June 29, 2022
+====================================
+- Fix test failure with some compilers.
+- Fix Telugu and Kannada kerning regression.
+
+
+Overview of changes leading to 4.4.0
+Monday, June 27, 2022
+====================================
+- Caching of variable fonts shaping, in particular when using HarfBuzz’s own
+ font loading functions (ot). Bringing performance of variable shaping in par
+ with non-variable fonts shaping. (Behdad Esfahbod)
+- Caching of format 2 “Contextual Substitution” and “Chained Contexts
+ Substitution” lookups. Resulting in up to 20% speedup of lookup-heavy fonts
+ like Gulzar or Noto Nastaliq Urdu. (Behdad Esfahbod)
+- Improved ANSI output from hb-view. (Behdad Esfahbod)
+- Support for shaping legacy, pre-OpenType Windows 3.1-era, Arabic fonts that
+ relied on a fixed PUA encoding. (Khaled Hosny, Behdad Esfahbod)
+- Sinhala script is now shaped by the USE shaper instead of “indic” one.
+ (Behdad Esfahbod, David Corbett)
+- Thai shaper improvements. (David Corbett)
+- hb-ot-name API supports approximate BCP-47 language matching, for example
+ asking for “en_US” in a font that has only “en” names will return them.
+ (Behdad Esfahbod)
+- Optimized TrueType glyph shape loading. (Behdad Esfahbod)
+- Fix subsetting of HarfBuzz faces created via hb_face_create_for_tables().
+ (Garret Rieger)
+- Add 32 bit var store support to the subsetter. (Garret Rieger)
+
+- New API
++HB_BUFFER_FLAG_DEFINED
++HB_BUFFER_SERIALIZE_FLAG_DEFINED
++hb_font_changed()
++hb_font_get_serial()
++hb_ft_hb_font_changed()
++hb_set_hash()
++hb_map_copy()
++hb_map_hash()
+
+
+Overview of changes leading to 4.3.0
+Friday, May 20, 2022
+====================================
+- Major speed up in loading and subsetting fonts, especially in
+ handling CFF table. Subsetting some fonts is now 3 times faster.
+ (Behdad Esfahbod, Garret Rieger)
+- Speed up blending CFF2 table. (Behdad Esfahbod)
+- Speed up hb_ot_tags_from_language(). (Behdad Esfahbod, David Corbett)
+- Fix USE classification of U+10A38 to fix multiple marks on single Kharoshthi
+ base. (David Corbett)
+- Fix parsing of empty CFF Index. (Behdad Esfahbod)
+- Fix subsetting CPAL table with partial palette overlaps. (Garret Rieger)
+
+- New API
++hb_map_is_equal() (Behdad Esfahbod)
+
+
+Overview of changes leading to 4.2.1
+Sunday, April 24, 2022
+====================================
+- Make sure hb_blob_create_from_file_or_fail() always returns nullptr in case
+ of failure and not empty blob sometimes. (Khaled Hosny)
+- Add --passthrough-tables option to hb-subset. (Cosimo Lupo)
+- Reinstate a pause after basic features in Khmer shaper, fixing a regression
+ introduced in previous release. (Behdad Esfahbod)
+- Better handling of Regional_Indicator when shaped with RTL-native scripts,
+ reverting earlier fix that caused regressions in AAT shaping. (Behdad Esfahbod)
+
+
+Overview of changes leading to 4.2.0
+Wednesday, March 30, 2022
+====================================
+- Source code reorganization, splitting large hb-ot-layout files into smaller,
+ per-subtable ones under OT/Layout/*. Code for more tables will follow suit in
+ later releases. (Garret Rieger, Behdad Esfahbod)
+- Revert Indic shaper change in previous release that broke some fonts and
+ instead make per-syllable restriction of “GSUB” application limited to
+ script-specific Indic features, while applying them and discretionary
+ features in one go. (Behdad Esfahbod)
+- Fix decoding of private in gvar table. (Behdad Esfahbod)
+- Fix handling of contextual lookups that delete too many glyphs. (Behdad Esfahbod)
+- Make “morx” deleted glyphs don’t block “GPOS” application. (Behdad Esfahbod)
+- Various build fixes. (Chun-wei Fan, Khaled Hosny)
+
+- New API
++hb_set_next_many() (Andrew John)
+
+
+Overview of changes leading to 4.1.0
+Wednesday, March 23, 2022
+====================================
+- Various OSS-Fuzz fixes. (Behdad Esfahbod)
+- Make fallback vertical-origin match FreeType’s. (Behdad Esfahbod)
+- Treat visible viramas like dependent vowels in USE shaper. (David Corbett)
+- Apply presentation forms features and discretionary features in one go in
+ Indic shaper, which seems to match Uniscribe and CoreText behaviour.
+ (Behdad Esfahbod, David Corbett)
+- Various bug fixes.
+
+- New API
++hb_set_add_sorted_array() (Andrew John)
+
+
+Overview of changes leading to 4.0.1
+Friday, March 11, 2022
+====================================
+- Update OpenType to AAT mappings for “hist” and “vrtr” features.
+ (Florian Pircher)
+- Update IANA Language Subtag Registry to 2022-03-02. (David Corbett)
+- Update USE shaper to allow any non-numeric tail in a symbol cluster, and
+ remove obsolete data overrides. (David Corbett)
+- Fix handling of baseline variations to return correctly scaled values.
+ (Matthias Clasen)
+- A new experimental hb_subset_repack_or_fail() to repack an array of objects,
+ eliminating offset overflows. The API is not available unless HarfBuzz is
+ built with experimental APIs enabled. (Qunxin Liu)
+
+- New experimental API
++hb_link_t
++hb_object_t
++hb_subset_repack_or_fail()
+
+
+Overview of changes leading to 4.0.0
+Tuesday, March 1, 2022
+====================================
+- New public API to create subset plan and gather information on things like
+ glyph mappings in the final subset. The plan can then be passed on to perform
+ the subsetting operation. (Garret Rieger)
+- Draw API for extracting glyph shapes have been extended and finalized and is
+ no longer an experimental API. The draw API supports glyf, CFF and CFF2
+ glyph outlines tables, and applies variation settings set on the font as well
+ as synthetic slant. The new public API is not backward compatible with the
+ previous, non-public, experimental API. (Behdad Esfahbod)
+- The hb-view tool will use HarfBuzz draw API to render the glyphs instead of
+ cairo-ft when compiled with Cairo 1.17.5 or newer, setting HB_DRAW
+ environment variable to 1 or 0 will force using or not use the draw API,
+ respectively. (Behdad Esfahbod)
+- The hb-shape and hb-view tools now default to using HarfBuzz’s own font
+ loading functions (ot) instead of FreeType ones (ft). They also have a new
+ option, --font-slant, to apply synthetic slant to the font. (Behdad Esfahbod)
+- HarfBuzz now supports more than 65535 (the OpenType limit) glyph shapes and
+ metrics. See https://github.com/be-fonts/boring-expansion-spec/issues/6 and
+ https://github.com/be-fonts/boring-expansion-spec/issues/7 for details.
+ (Behdad Esfahbod)
+- New API to get the dominant horizontal baseline tag for a given script.
+ (Behdad Esfahbod)
+- New API to get the baseline positions from the font, and synthesize missing
+ ones. As well as new API to get font metrics and synthesize missing ones.
+ (Matthias Clasen)
+- Improvements to finding dependencies on Windows when building with Visual
+ Studio. (Chun-wei Fan)
+- New buffer flag, HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT, that must be set
+ during shaping for HB_GLYPH_FLAG_UNSAFE_TO_CONCAT flag to be reliably
+ produced. This is to limit the performance hit of producing this flag to when
+ it is actually needed. (Behdad Esfahbod)
+- Documentation improvements. (Matthias Clasen)
+
+- New API
+ - General:
+ +HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
+ +hb_var_num_t
+
+ - Draw:
+ +hb_draw_funcs_t
+ +hb_draw_funcs_create()
+ +hb_draw_funcs_reference()
+ +hb_draw_funcs_destroy()
+ +hb_draw_funcs_is_immutable()
+ +hb_draw_funcs_make_immutable()
+ +hb_draw_move_to_func_t
+ +hb_draw_funcs_set_move_to_func()
+ +hb_draw_line_to_func_t
+ +hb_draw_funcs_set_line_to_func()
+ +hb_draw_quadratic_to_func_t
+ +hb_draw_funcs_set_quadratic_to_func()
+ +hb_draw_cubic_to_func_t
+ +hb_draw_funcs_set_cubic_to_func()
+ +hb_draw_close_path_func_t
+ +hb_draw_funcs_set_close_path_func()
+ +hb_draw_state_t
+ +HB_DRAW_STATE_DEFAULT
+ +hb_draw_move_to()
+ +hb_draw_line_to()
+ +hb_draw_quadratic_to()
+ +hb_draw_cubic_to()
+ +hb_draw_close_path()
+ +hb_font_get_glyph_shape_func_t
+ +hb_font_funcs_set_glyph_shape_func()
+ +hb_font_get_glyph_shape()
+
+ - OpenType layout
+ +HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL
+ +HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL
+ +hb_ot_layout_get_horizontal_baseline_tag_for_script()
+ +hb_ot_layout_get_baseline_with_fallback()
+
+ - Metrics:
+ +hb_ot_metrics_get_position_with_fallback()
+
+ - Subset:
+ +hb_subset_plan_t
+ +hb_subset_plan_create_or_fail()
+ +hb_subset_plan_reference()
+ +hb_subset_plan_destroy()
+ +hb_subset_plan_set_user_data()
+ +hb_subset_plan_get_user_data()
+ +hb_subset_plan_execute_or_fail()
+ +hb_subset_plan_unicode_to_old_glyph_mapping()
+ +hb_subset_plan_new_to_old_glyph_mapping()
+ +hb_subset_plan_old_to_new_glyph_mapping()
+
+
+Overview of changes leading to 3.4.0
+Sunday, February 13, 2022
+====================================
+- Perform sanity checks on shaping results is now part of “harfbuzz” library
+ and can be enabled by setting the buffer flag HB_BUFFER_FLAG_VERIFY.
+ (Behdad Esfahbod)
+- Arabic Mark Transient Reordering Algorithm have been updated to revision 6.
+ (Khaled Hosny)
+- ISO 15924 code for mathematical notation, ‘Zmth’, now maps to the OpenType
+ ‘math’ tag. (Alexis King)
+- It is now possible to get at once all math kerning values for a given glyph
+ at a given corner. (Alexis King)
+- Fix locale_t portability issues on systems the typedef’s it to a void
+ pointer. (Behdad Esfahbod)
+
+- New API:
++HB_BUFFER_FLAG_VERIFY
++HB_OT_TAG_MATH_SCRIPT
++HB_SCRIPT_MATH
++hb_ot_math_kern_entry_t
++hb_ot_math_get_glyph_kernings()
+
+- Deprecated API
++HB_OT_MATH_SCRIPT
+
+
+Overview of changes leading to 3.3.2
+Sunday, February 6, 2022
+====================================
+- Revert splitting of pair positioning values introduced in 3.3.0 as it proved
+ problematic. (Behdad Esfahbod)
+
+
+Overview of changes leading to 3.3.1
+Monday, January 31, 2022
+====================================
+- Fix heap-use-after-free in harfbuzz-subset introduced in previous release.
+ (Garret Rieger)
+
+
+Overview of changes leading to 3.3.0
+Monday, January 31, 2022
+====================================
+- Improved documentation. (Matthias Clasen)
+- Internal code cleanup, using C++ standard library more. (Behdad Esfahbod)
+- The low 16-bits of face index will be used by hb_face_create() to select a
+ face inside a font collection file format, while the high 16-bits will be
+ used by hb_font_create() to load the named instance. (Behdad Esfahbod)
+- Glyph positions and other font metrics now apply synthetic slant set by
+ hb_font_set_synthetic_slant(), for improved positioning for synthetically
+ slanted fonts. (Behdad Esfahbod)
+- Fixed unintentional locale dependency in hb_variation_to_string() for decimal
+ point representation. (Matthias Clasen)
+- When applying pair positioning (kerning) the positioning value is split
+ between the two sides of the pair for improved cursor positioning between
+ such pairs. (Behdad Esfahbod)
+- Introduced new HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, to be used in conjunction
+ with HB_GLYPH_FLAG_UNSAFE_TO_BREAK for optimizing re-shaping during line
+ breaking. Check the documentation for further details. (Behdad Esfahbod)
+- Improved handling of macrolanguages when mapping BCP 47 codes to OpenType
+ tags. (David Corbett)
+
+- New API:
++HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
++hb_segment_properties_overlay()
++hb_buffer_create_similar()
++hb_font_set_synthetic_slant()
++hb_font_get_synthetic_slant()
++hb_font_get_var_coords_design()
+
+
+Overview of changes leading to 3.2.0
+Friday, November 26, 2021
+====================================
+“harfbuzz” library improvements:
+- Fixed shaping of Apple Color Emoji flags in right-to-left context. (Behdad Esfahbod)
+- Fixed positioning of CFF fonts in HB_TINY profile. (Behdad Esfahbod)
+- OpenType 1.9 language tags update. (David Corbett)
+- Add HB_NO_VERTICAL config option.
+- Add HB_CONFIG_OVERRIDE_H for easier configuration. (Behdad Esfahbod)
+
+“harfbuzz-subset” library improvements:
+- Improved packing of cmap, loca, and Ligature tables. (Garret Rieger)
+- Significantly improved overflow-resolution strategy in the repacker. (Garret Rieger)
+
+
+Overview of changes leading to 3.1.2
+Friday, November 26, 2021
+====================================
+- hb-shape / hb-view: revert treating text on the commandline as single
+ paragraph (was introduced in 3.0.0); add new --single-par to do that.
+ (Behdad Esfahbod)
+- Subsetter bug fixes. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
+
+
Overview of changes leading to 3.1.1
Wednesday, November 8, 2021
====================================
@@ -359,7 +840,7 @@ Friday, May 24, 2019
code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
dropped.
- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
-- New Unicode Character Databse implementation that is half the size of previously-used
+- New Unicode Character Database implementation that is half the size of previously-used
UCDN.
- Subsetter improvements.
- Improved documentation, thanks to Nathan Willis.
@@ -1207,7 +1688,7 @@ Thursday, February 25, 2016
due to bug in glyph class of ASCII double-quote character. This should
address "regression" introduced in 1.2.0 when we switched mark zeroing
in most shapers from BY_UNICODE_LATE to BY_GDEF_LATE.
- This fourth release in a week should finally stablize things...
+ This fourth release in a week should finally stabilize things...
- hb-ot-font's get_glyph() implementation saw some optimizations. Though,
might be really hard to measure in real-world situations.
@@ -2255,7 +2736,7 @@ o Changed API:
- hb_buffer_create() takes zero arguments now.
Use hb_buffer_pre_allocate() to pre-allocate.
- - hb_buffer_add_utf*() now accept -1 for length parameteres,
+ - hb_buffer_add_utf*() now accept -1 for length parameters,
meaning "nul-terminated".
- hb_direction_t enum values changed.
diff --git a/OWNERS b/OWNERS
index 9bc89fbf2..9805094c9 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,3 @@
-behdad@google.com
siyamed@google.com
nona@google.com
jungshik@google.com
diff --git a/README b/README
index 84c542f8a..42061c01a 100644..120000
--- a/README
+++ b/README
@@ -1,15 +1 @@
-This is HarfBuzz, a text shaping library.
-
-For bug reports, mailing list, and other information please visit:
-
- http://harfbuzz.org/
-
-For license information, see https://github.com/harfbuzz/harfbuzz/blob/main/COPYING
-
-For build information, see https://github.com/harfbuzz/harfbuzz/blob/main/BUILD.md
-
-For custom configurations, see https://github.com/harfbuzz/harfbuzz/blob/main/CONFIG.md
-
-For test execution, see https://github.com/harfbuzz/harfbuzz/blob/main/TESTING.md
-
-Documentation: https://harfbuzz.github.io
+README.md \ No newline at end of file
diff --git a/README.md b/README.md
index 9deb32c1e..4202961e0 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,17 @@
[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
-[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
-[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
-[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
-[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
-This is HarfBuzz, a text shaping library.
+# HarfBuzz
+
+HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
+[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
+ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt,
+XeTeX, and other places.
For bug reports, mailing list, and other information please visit:
@@ -16,14 +19,66 @@ For bug reports, mailing list, and other information please visit:
For license information, see [COPYING](COPYING).
+## Documentation
+
+For user manual as well as API documentation, check: https://harfbuzz.github.io
+
+## Download
+
+For tarball releases of HarfBuzz, look [here][3]. At the same place you
+will also find Win32/Win64 binary bundles that include libharfbuzz DLL,
+hb-view.exe, hb-shape.exe, and all dependencies.
+
+The canonical source tree is available on [github][4].
+
+The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
+headers are more likely to go through minor modifications, but again, we do our
+best to never change API in an incompatible way. We will never break the ABI.
+
+If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
+HarfBuzz][5].
+
+## Development
+
For build information, see [BUILD.md](BUILD.md).
For custom configurations, see [CONFIG.md](CONFIG.md).
-For test execution, see [TESTING.md](TESTING.md).
+For testing and profiling, see [TESTING.md](TESTING.md).
-Documentation: https://harfbuzz.github.io
+To get a better idea of where HarfBuzz stands in the text rendering stack you
+may want to read [State of Text Rendering][6], though, that document is many
+years old. Here are a few presentation slides about HarfBuzz at the
+Internationalization and Unicode Conference over the years:
+* November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
+* October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
+* October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
+
+Both development and user support discussion around HarfBuzz happens on the
+[github][4].
+
+To report bugs or submit patches please use [github][4] issues and
+pull-requests.
+
+For a comparison of old vs new HarfBuzz memory consumption see [this][10].
+
+<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
+
+## Name
+
+HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It sports a second meaning, but that
+ain’t translatable.
+
+> Background: Originally there was this font format called TrueType. People and
+> companies started calling their type engines all things ending in Type:
+> FreeType, CoolType, ClearType, etc. And then came OpenType, which is the
+> successor of TrueType. So, for my OpenType implementation, I decided to stick
+> with the concept but use the Persian translation. Which is fitting given that
+> Persian is written in the Arabic script, and OpenType is an extension of
+> TrueType that adds support for complex script rendering, and HarfBuzz is an
+> implementation of OpenType complex text shaping.
<details>
<summary>Packaging status of HarfBuzz</summary>
@@ -31,3 +86,14 @@ Documentation: https://harfbuzz.github.io
[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
</details>
+
+[1]: https://docs.microsoft.com/en-us/typography/opentype/spec/
+[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
+[3]: https://github.com/harfbuzz/harfbuzz/releases
+[4]: https://github.com/harfbuzz/harfbuzz
+[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
+[6]: http://behdad.org/text/
+[7]: https://goo.gl/FSIQuC
+[8]: https://goo.gl/2wSRu
+[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
+[10]: https://goo.gl/woyty
diff --git a/README.mingw.md b/README.mingw.md
index d9bd34740..60629f6fc 100644
--- a/README.mingw.md
+++ b/README.mingw.md
@@ -29,6 +29,12 @@ for reference.
- 32bit: `../mingw-configure.sh i686`
- 64bit: `../mingw-configure.sh x86_64`
+ c) Build as usual:
+ - make
+
+ d) Configure your wine to find system mingw libraries. See:
+ https://fedoraproject.org/wiki/MinGW/Configure_wine
+
Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)`
but if you like to shape with the Microsoft Uniscribe:
@@ -45,3 +51,8 @@ but if you like to shape with the Microsoft Uniscribe:
5. `WINEDLLOVERRIDES="usp10=n" wine hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
+
+When you have built that, you can test HarfBuzz's native shaper against Uniscribe
+following these instructions:
+
+ https://github.com/harfbuzz/harfbuzz/issues/3671
diff --git a/README.version b/README.version
deleted file mode 100644
index 6a89497cb..000000000
--- a/README.version
+++ /dev/null
@@ -1,3 +0,0 @@
-URL: https://github.com/harfbuzz/harfbuzz/commit/cd5c6cd0419ac5e4de975d6c476fb760bf06d2ce
-Version: 3.1.1
-BugComponent: 25699
diff --git a/RELEASING.md b/RELEASING.md
index 67d63103b..8d5a4060b 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -28,7 +28,7 @@
- [ ] Commit NEWS, meson.build, configure.ac, and src/hb-version.h, as well as any REPLACEME changes you made.
The commit message is simply the release number, e. g. "1.4.7"
-- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest commited changes.
+- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes.
If doesn't pass, something fishy is going on, reset the repo and start over.
- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
diff --git a/TESTING.md b/TESTING.md
index c72283455..18d702027 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -39,17 +39,9 @@ ninja -C build
## Test with the Fuzzer
-```shell
-CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer" -Dexperimental_api=true
-ninja -Cfuzzbuild test/fuzzing/hb-{shape,draw,subset,set}-fuzzer
-fuzzbuild/test/fuzzing/hb-subset-fuzzer test/fuzzing/fonts
-```
+FOr fuzzing, see `test/fuzzing/README.md`.
## Profiling
-```
-meson build --reconfigure
-meson compile -C build
-build/perf/perf
-```
+For profiling, see `perf/README.md`.
diff --git a/TODO b/TODO
deleted file mode 100644
index d8e41050e..000000000
--- a/TODO
+++ /dev/null
@@ -1,28 +0,0 @@
-API issues:
-===========
-
-- API to accept a list of languages?
-
-- Remove hb_ot_shape_glyphs_closure()?
-
-
-API additions
-=============
-
-- Language to/from script.
-
-- Add hb-cairo glue
-
-- Add sanitize API.
-
-- Add query / enumeration API for aalt-like features?
-
-- Add segmentation API
-
-- Add hb-fribidi glue?
-
-
-hb-view / hb-shape enhancements:
-===============================
-
-- Add --width, --height, --auto-size, --ink-box, --align, etc?
diff --git a/configure.ac b/configure.ac
index 0acbba364..abe86ede5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
- [3.1.1],
+ [6.0.0],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@@ -68,8 +68,8 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
])
# Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
-AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h)
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale)
+AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
# Compiler flags
AC_CANONICAL_HOST
@@ -194,6 +194,10 @@ AC_ARG_WITH(cairo,
have_cairo=false
if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then
PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :)
+ save_libs=$LIBS
+ LIBS="$LIBS $CAIRO_LIBS"
+ AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func)
+ LIBS=$save_libs
fi
if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
AC_MSG_ERROR([cairo support requested but not found])
@@ -304,7 +308,7 @@ if $have_freetype; then
AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
save_libs=$LIBS
LIBS="$LIBS $FREETYPE_LIBS"
- AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
+ AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
LIBS=$save_libs
fi
AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@@ -362,17 +366,13 @@ AC_ARG_WITH(directwrite,
have_directwrite=false
AC_LANG_PUSH([C++])
if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
- AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
+ AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true)
fi
AC_LANG_POP([C++])
if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
AC_MSG_ERROR([directwrite support requested but not found])
fi
if $have_directwrite; then
- DIRECTWRITE_CXXFLAGS=
- DIRECTWRITE_LIBS=
- AC_SUBST(DIRECTWRITE_CXXFLAGS)
- AC_SUBST(DIRECTWRITE_LIBS)
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
fi
AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
@@ -433,6 +433,8 @@ test/shape/data/text-rendering-tests/Makefile
test/subset/Makefile
test/subset/data/Makefile
test/subset/data/repack_tests/Makefile
+test/threads/Makefile
+perf/Makefile
docs/Makefile
docs/version.xml
])
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 5c03209a3..36da8ae37 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -83,7 +83,7 @@ content_files= \
usermanual-integration.xml \
version.xml
-# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
diff --git a/docs/features.dot b/docs/features.dot
new file mode 100644
index 000000000..88cb3faeb
--- /dev/null
+++ b/docs/features.dot
@@ -0,0 +1,259 @@
+digraph {
+ graph [outputorder=edgefirst];
+ node [shape="record", fontname="Noto Sans Mono SemiBold", fontsize=15];
+ edge [fontname="Verdana", fontsize=12,labeldistance=7.5 ];
+ fontname="Verdana";
+ ranksep=0.02; nodesep=0.5;
+
+subgraph {
+ ranksep="0.02 equally";
+ preprocessing[style=filled,fillcolor="lightgreen",fontname="Verdana",label="Glyph pre-processing"];
+ orthographic[style=filled,fillcolor="lightblue",fontname="Verdana",label="Orthographic Unit Shaping"];
+ reordering[style=filled, fillcolor="lightcoral",fontname="Verdana",label="Reordering group (USE)"];
+ topographic[style=filled,fillcolor="lightgoldenrod",fontname="Verdana",label="Topographical Features‡"];
+ typographic[style=filled,fillcolor="lightpink",fontname="Verdana",label="Typographic Presentation"];
+ positioning[style=filled,fillcolor="lightsalmon",fontname="Verdana",label="Positioning"];
+ preprocessing->reordering->orthographic->topographic->typographic->positioning;
+}
+
+ decision1 [shape="diamond", label="Script\ndirection?",fontname="Verdana"];
+ rvrn->decision1;
+
+ ltrfeatures [label="{ltra|ltrm}", fillcolor="lightgreen",style="filled"];
+ {
+ rtlfeatures [label="{rtla|rtlm¹}", fillcolor="lightgreen",style="filled"];
+ }
+ {
+ rank=same;
+ fracfeatures [label="frac²|numr³|dnom⁴", fillcolor="lightpink",style="filled"];
+ fracnotes [fontname="Verdana",shape=plaintext,label=<<table border="0" cellborder="0" cellspacing="0">
+ <tr><td align="left">¹ rtlm is scoped to characters with a Unicode mirroring property</td></tr>
+ <tr><td align="left">² frac is scoped to numr + the slash + dnom</td></tr>
+ <tr><td align="left">³ numr is scoped to all decimal numbers before a U+2044 FRACTION SLASH.</td></tr>
+ <tr><td align="left">⁴ dnom is scoped to all decimal numbers after a U+2044 FRACTION SLASH.</td></tr>
+ </table>
+ >];
+
+ }
+ rand [fillcolor="lightpink",style="filled"];
+
+ decision1 -> ltrfeatures [label="Left-to-right"];
+ decision1 -> rtlfeatures [label="Right-to-left"];
+
+ decision1 -> fracfeatures [label="Other"];
+
+ ltrfeatures -> fracfeatures;
+ rtlfeatures -> fracfeatures;
+ fracfeatures->rand;
+
+ decision2 [shape="diamond", label="Script?",fontname="Verdana"];
+
+{rank=same; HARF [label="{Harf|HARF}"]; notes;}
+ rand -> trak -> HARF -> decision2;
+
+ commonfeatures [shape=none,label=<<table border="0" cellspacing="0">
+ <tr>
+ <td border="1" bgcolor="lightsalmon">abvm</td>
+ <td border="1" bgcolor="lightsalmon">blwm</td>
+ <td border="1" bgcolor="lightgreen">ccmp</td>
+ <td border="1" bgcolor="lightgreen">locl</td>
+ <td border="1" bgcolor="lightsalmon">mark</td>
+ <td border="1" bgcolor="lightsalmon">mkmk</td>
+ <td border="1" bgcolor="lightpink">rlig</td>
+ </tr>
+ </table>>
+ ];
+
+ decision3 [shape="diamond", label="Script\ndirection?",fontname="Verdana"];
+
+ BUZZ [label="{Buzz|BUZZ}"];
+ BUZZ -> commonfeatures -> decision3;
+
+ horizontalfeatures [
+ shape=none,label=<<table border="0" cellspacing="0">
+ <tr><td border="1" bgcolor="lightpink">calt <font face="Verdana">(not Hangul)</font></td></tr>
+ <tr><td border="1" bgcolor="lightpink">clig <font face="Verdana">(not Khmer)</font></td></tr>
+ <tr><td border="1" bgcolor="lightsalmon">curs</td></tr>
+ <tr><td border="1" bgcolor="lightsalmon">dist</td></tr>
+ <tr><td border="1" bgcolor="lightsalmon">kern</td></tr>
+ <tr><td border="1" bgcolor="lightpink">liga <font face="Verdana">(not Khmer)</font></td></tr>
+ <tr><td border="1" bgcolor="lightpink">rclt</td></tr>
+ </table>>
+ ];
+ vert [label="vert",style=filled,fillcolor="lightpink"];
+
+ decision3 -> horizontalfeatures [label="Horizontal"];
+ decision3 -> vert [label="Vertical"];
+
+ discretionary [label="User-selected\ndiscretionary\nfeatures",fontname="Verdana"];
+
+ horizontalfeatures -> discretionary;
+ vert -> discretionary;
+
+ decision2->stch;
+
+ BUZZ;
+
+subgraph shapers {
+ subgraph cluster_arabic {
+ bgcolor="lightyellow"
+ label="Arabic, Syriac";
+ stch [ style="filled", fillcolor="lightgreen",label="stch"];
+ ccmplocl [ style="filled", label="ccmp|locl", fillcolor="lightgreen"];
+ arabicfeatures [label="isol|fina|fin2|fin3|medi|med2|init", style="filled", fillcolor="lightgoldenrod"];
+ arabicfeatures2 [label="rclt|calt", style="filled",fillcolor="lightpink"];
+rlig[style="filled",fillcolor="lightpink"];
+mset [fillcolor="lightpink",style="filled"]
+ stch->ccmplocl->arabicfeatures->rlig->arabicfeatures2->mset;
+ }
+ mset->BUZZ:n;
+
+ subgraph cluster_hangul {
+ bgcolor="lightyellow"
+ label="Hangul";
+ hangulfeatures [label="ljmo|vjmo|tjmo", style="filled",fillcolor="lightgoldenrod"]
+ }
+ hangulfeatures->BUZZ:n;
+
+ subgraph cluster_indic {
+ label="Indic";
+ bgcolor="lightyellow"
+ // Preprocessing
+ loclccmpindic [label="locl†|ccmp†",style=filled,fillcolor="lightgreen"];
+ node[style=filled,fillcolor="lightgreen"];
+ nukt [label="nukt†"];
+ akhn [label="akhn†"];
+ loclccmpindic->indic_reorder_1->nukt->akhn;
+ indic_reorder_1[label="Initial reordering", fontname="Verdana",fillcolor="lightgrey",shape=ellipse,style=filled]
+
+ // Orthographic
+ node[style=filled,fillcolor="lightblue"]
+ rphf [label="rphf⁵"];
+ rkpf [label="rkpf†"];
+ pref [label="pref⁶"];
+ blwf [label="blwf⁷"];
+ abvf [label="abvf⁸"];
+ half [label="half⁹"];
+ pstf [label="pstf⁸"];
+ vatu [label="vatu†"];
+ cjct [label="cjct†"];
+ akhn ->rphf -> rkpf -> pref -> blwf -> abvf -> half -> pstf -> vatu -> cjct;
+ // Typographic presentation
+ indic_typographic[style=filled,fillcolor="lightpink",label="init|pres|abvs|blws|psts|haln"]
+ indic_reorder_2[label="Final reordering",fillcolor="lightgrey",fontname="Verdana", shape=ellipse,style=filled]
+ cjct->indic_reorder_2->indic_typographic;
+
+ notes2 [fontname="Verdana",shape=plaintext,style="",label=<<table border="0" cellborder="0" cellspacing="0">
+<tr><td align="right">⁵ rphf is scoped to pre-base ra+halant sequences</td></tr>
+<tr><td align="right">⁶ pref is scoped to the two glyphs after the base; outputs are reordered</td></tr>
+<tr><td align="right">⁷ blwf is usually scoped to the whole syllable, except in Telugu and Kannada where it is post-base</td></tr>
+<tr><td align="right">⁸ abvf and pstf are scoped to post-base</td></tr>
+<tr><td align="right">⁹ half is scoped to pre-base</td></tr>
+</table>
+>];
+ indic_typographic -> notes2 [style=invis];
+ }
+
+
+ subgraph cluster_khmer {
+ label="Khmer";
+ bgcolor="lightyellow"
+
+ khmerbasic [style=filled,fillcolor="lightgreen",label="locl†|ccmp†|pref†|bwlf†|abvf†|pstf†|cfar†"]
+ khmerother [style=filled,fillcolor="lightpink",label="pres|abvs|blws|psts"]
+ khmerbasic -> khmerother -> khmerclig;
+ khmerclig [label="clig",style=filled,fillcolor="lightpink"];
+ }
+
+ subgraph cluster_myanmar {
+ label="Myanmar";
+ bgcolor="lightyellow"
+ loclccmpmyanmar [label="locl†|ccmp†",style=filled,fillcolor="lightgreen"];
+ rphfmymr [label="rphf†",style=filled,fillcolor="lightblue"]
+ prefmymr [label="pref†",style=filled,fillcolor="lightblue"]
+ blwfmymr [label="blwf†",style=filled,fillcolor="lightblue"]
+ pstfmymr [label="pstf†",style=filled,fillcolor="lightblue"]
+ myanmarother [label="pres|abvs|blws|psts",style=filled,fillcolor="lightpink"];
+ reorder_myanmar[label="Reordering", shape=ellipse,style=filled,fontname="Verdana"]
+ loclccmpmyanmar -> reorder_myanmar-> rphfmymr -> prefmymr -> blwfmymr -> pstfmymr -> myanmarother;
+ }
+
+ subgraph cluster_use {
+ label="Universal Shaping Engine"
+ bgcolor="lightyellow"
+ use_preprocessing [style=filled, label="locl†|ccmp†|nukt†|akhn†", fillcolor="lightgreen"];
+ // Reoredering
+ rphfuse [label="rphf¹⁰", style=filled, fillcolor="lightcoral"];
+ prefuse [label="pref¹¹", style=filled, fillcolor="lightcoral"];
+ // Orthographic
+ orthographicuse [label="rkrf†|abvf†|blwf†|half†|pstf†|vatu†|cjct†", style="filled", fillcolor="lightblue"];
+ topographicaluse [label="isol|init|medi|fina", style="filled", fillcolor="lightgoldenrod"];
+ typographicaluse [label="abvs|blws|haln|pres|psts", style="filled", fillcolor="lightpink"];
+ reorder_use[label="Reordering", shape=ellipse,style=filled,fontname="Verdana"]
+ use_preprocessing -> rphfuse -> prefuse->orthographicuse ->reorder_use -> topographicaluse -> typographicaluse;
+ notes3 [fontname="Verdana",shape=plaintext,label=<<table border="0" cellborder="0" cellspacing="0">
+ <tr><td align="left">¹⁰ Outputs are reordered as category R</td></tr>
+ <tr><td align="left">¹¹ Outputs are reordered to before base</td></tr>
+ </table>
+ >];
+ typographicaluse -> notes3 [style=invis];
+ }
+
+}
+
+ indic_typographic->BUZZ:n;
+ typographicaluse->BUZZ:n;
+ khmerclig -> BUZZ:n;
+ myanmarother -> BUZZ:n;
+
+
+ decision2->hangulfeatures;
+ decision2->loclccmpindic;
+ decision2->khmerbasic;
+ decision2->loclccmpmyanmar;
+ decision2->use_preprocessing;
+ decision2->BUZZ [label=" Hebrew, Thai,\n Lao, other"];
+
+notes [fontname="Verdana",shape=box,label=<<table border="0" cellborder="0" cellspacing="0">
+ <tr><td align="left">
+<b>Indic</b> scripts are: Bengali, Devanagari,
+ Gujarati, Gurmukhi, Kannada,
+ Malayalam, Oriya, Tamil,
+ Telugu
+</td></tr>
+
+ <tr><td align="left">
+<b>USE</b> scripts are:
+ Adlam, Ahom, Balinese, Batak, Bhaiksuki, Brahmi, Buginese,
+ Buhid, Chakma, Cham, Chorasmian, Dives Akuru, Dogra, Duployan,
+</td></tr>
+ <tr><td align="left">
+Egyptian hieroglyphs, Elymaic, Grantha, Gunjala Ggondi, Hanifi Rohingya,
+ Hanunoo, Javanese, Kaithi, Kayah li, Kharoshthi, Khojki,
+</td></tr>
+ <tr><td align="left">
+Khudawadi, Lepcha, Limbu, Mahajani, Makasar, Mandaic, Manichaean,
+ Marchen, Masaram Gondi, Medefaidrin, Meetei Mayek, Miao, Modi,
+</td></tr>
+ <tr><td align="left">
+Mongolian, Multani, Nandinagari, Newa, Nko, Nyiakeng Puachue Hmong,
+ Old Sogdian, Pahawh Hmong, Phags Pa, Psalter Pahlavi, Rejang,
+</td></tr>
+ <tr><td align="left">
+Saurashtra, Sharada, Siddham, Sinhala, Sogdian, Soyombo, Sundanese,
+ Syloti Nagri, Tagalog, Tagbanwa, Tai Le, Tai Tham, Tai Viet,
+</td></tr>
+ <tr><td align="left">
+Takri, Tibetan, Tifinagh, Tirhuta, Wancho, Zanabazar square,
+</td></tr>
+
+</table>>]
+
+
+ footnote[fontname="Verdana",label=<<table border="0" cellborder="0" cellspacing="0">
+ <tr><td align="left">† Feature is scoped to each syllable</td></tr>
+ <tr><td align="left">‡ All topographic features are scoped based on topographic position</td></tr>
+ </table>>];
+ notes3->footnote[style=invis];
+
+}
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 5fa365898..2d2827a66 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -56,6 +56,7 @@
<xi:include href="xml/hb-blob.xml"/>
<xi:include href="xml/hb-buffer.xml"/>
<xi:include href="xml/hb-common.xml"/>
+ <xi:include href="xml/hb-draw.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-face.xml"/>
<xi:include href="xml/hb-font.xml"/>
@@ -116,6 +117,16 @@
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-6-0-0" role="6.0.0"><title>Index of new symbols in 6.0.0</title><xi:include href="xml/api-index-6.0.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-5-3-0" role="5.3.0"><title>Index of new symbols in 5.3.0</title><xi:include href="xml/api-index-5.3.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-5-0-0" role="5.0.0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-4-4-0" role="4.4.0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-4-3-0" role="4.3.0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-4-2-0" role="4.2.0"><title>Index of new symbols in 4.2.0</title><xi:include href="xml/api-index-4.2.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-4-1-0" role="4.1.0"><title>Index of new symbols in 4.1.0</title><xi:include href="xml/api-index-4.1.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-4-0-0" role="4.0.0"><title>Index of new symbols in 4.0.0</title><xi:include href="xml/api-index-4.0.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-3-4-0" role="3.4.0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
+ <index id="api-index-3-3-0" role="3.3.0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-1-0" role="3.1.0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-0-0" role="3.0.0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-1" role="2.9.1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
@@ -138,7 +149,6 @@
<index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
- <index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-2" role="1.7.2"><title>Index of new symbols in 1.7.2</title><xi:include href="xml/api-index-1.7.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index f2c75930d..a35d3aa39 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -26,32 +26,33 @@ hb_blob_create_from_file
hb_blob_create_from_file_or_fail
hb_blob_create_sub_blob
hb_blob_copy_writable_or_fail
+hb_blob_get_empty
+hb_blob_reference
hb_blob_destroy
+hb_blob_set_user_data
+hb_blob_get_user_data
+hb_blob_make_immutable
+hb_blob_is_immutable
hb_blob_get_data
hb_blob_get_data_writable
-hb_blob_get_empty
hb_blob_get_length
-hb_blob_get_user_data
-hb_blob_is_immutable
-hb_blob_make_immutable
-hb_blob_reference
-hb_blob_set_user_data
hb_blob_t
hb_memory_mode_t
</SECTION>
<SECTION>
<FILE>hb-buffer</FILE>
-HB_SEGMENT_PROPERTIES_DEFAULT
-HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
hb_buffer_create
-hb_buffer_reference
+hb_buffer_allocation_successful
+hb_buffer_create_similar
hb_buffer_get_empty
+hb_buffer_reference
hb_buffer_destroy
+hb_buffer_set_user_data
+hb_buffer_get_user_data
hb_buffer_reset
hb_buffer_clear_contents
hb_buffer_pre_allocate
-hb_buffer_allocation_successful
hb_buffer_add
hb_buffer_add_codepoints
hb_buffer_add_utf32
@@ -78,15 +79,14 @@ hb_buffer_get_segment_properties
hb_buffer_guess_segment_properties
hb_buffer_set_unicode_funcs
hb_buffer_get_unicode_funcs
-hb_buffer_set_user_data
-hb_buffer_get_user_data
hb_buffer_get_glyph_infos
+hb_glyph_info_get_glyph_flags
hb_buffer_get_glyph_positions
hb_buffer_has_positions
-hb_buffer_get_invisible_glyph
hb_buffer_set_invisible_glyph
-hb_buffer_get_not_found_glyph
+hb_buffer_get_invisible_glyph
hb_buffer_set_not_found_glyph
+hb_buffer_get_not_found_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs
@@ -103,10 +103,13 @@ hb_buffer_serialize_format_to_string
hb_buffer_serialize_list_formats
hb_segment_properties_equal
hb_segment_properties_hash
+hb_segment_properties_overlay
hb_buffer_diff
+hb_buffer_message_func_t
hb_buffer_set_message_func
+HB_SEGMENT_PROPERTIES_DEFAULT
+HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
hb_buffer_t
-hb_glyph_info_get_glyph_flags
hb_glyph_info_t
hb_glyph_flags_t
hb_glyph_position_t
@@ -117,22 +120,30 @@ hb_segment_properties_t
hb_buffer_serialize_format_t
hb_buffer_serialize_flags_t
hb_buffer_diff_flags_t
-hb_buffer_message_func_t
</SECTION>
<SECTION>
<FILE>hb-common</FILE>
+HB_TAG
+HB_UNTAG
hb_tag_from_string
hb_tag_to_string
hb_direction_from_string
hb_direction_to_string
+HB_DIRECTION_REVERSE
+HB_DIRECTION_IS_BACKWARD
+HB_DIRECTION_IS_FORWARD
+HB_DIRECTION_IS_HORIZONTAL
+HB_DIRECTION_IS_VALID
+HB_DIRECTION_IS_VERTICAL
hb_script_from_iso15924_tag
-hb_script_from_string
hb_script_to_iso15924_tag
+hb_script_from_string
hb_script_get_horizontal_direction
hb_language_from_string
hb_language_to_string
hb_language_get_default
+hb_language_matches
hb_feature_from_string
hb_feature_to_string
hb_variation_from_string
@@ -149,24 +160,21 @@ hb_position_t
hb_tag_t
hb_script_t
hb_user_data_key_t
-HB_TAG
HB_TAG_NONE
HB_TAG_MAX
HB_TAG_MAX_SIGNED
-HB_UNTAG
-HB_DIRECTION_REVERSE
-HB_DIRECTION_IS_BACKWARD
-HB_DIRECTION_IS_FORWARD
-HB_DIRECTION_IS_HORIZONTAL
-HB_DIRECTION_IS_VALID
-HB_DIRECTION_IS_VERTICAL
HB_LANGUAGE_INVALID
HB_FEATURE_GLOBAL_END
HB_FEATURE_GLOBAL_START
+HB_HAS_CORETEXT
+HB_HAS_FREETYPE
+HB_HAS_GLIB
+HB_HAS_GRAPHITE
<SUBSECTION Private>
HB_BEGIN_DECLS
HB_END_DECLS
hb_var_int_t
+hb_var_num_t
int16_t
int32_t
int64_t
@@ -175,13 +183,39 @@ uint16_t
uint32_t
uint64_t
uint8_t
-<SUBSECTION Private>
HB_EXTERN
HB_DEPRECATED
HB_DEPRECATED_FOR
</SECTION>
<SECTION>
+<FILE>hb-draw</FILE>
+hb_draw_funcs_create
+hb_draw_funcs_reference
+hb_draw_funcs_destroy
+hb_draw_funcs_make_immutable
+hb_draw_funcs_is_immutable
+hb_draw_move_to_func_t
+hb_draw_funcs_set_move_to_func
+hb_draw_line_to_func_t
+hb_draw_funcs_set_line_to_func
+hb_draw_quadratic_to_func_t
+hb_draw_funcs_set_quadratic_to_func
+hb_draw_cubic_to_func_t
+hb_draw_funcs_set_cubic_to_func
+hb_draw_close_path_func_t
+hb_draw_funcs_set_close_path_func
+hb_draw_move_to
+hb_draw_line_to
+hb_draw_quadratic_to
+hb_draw_cubic_to
+hb_draw_close_path
+HB_DRAW_STATE_DEFAULT
+hb_draw_funcs_t
+hb_draw_state_t
+</SECTION>
+
+<SECTION>
<FILE>hb-deprecated</FILE>
HB_BUFFER_FLAGS_DEFAULT
HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
@@ -189,6 +223,7 @@ HB_SCRIPT_CANADIAN_ABORIGINAL
hb_font_funcs_set_glyph_func
hb_font_get_glyph_func_t
HB_MATH_GLYPH_PART_FLAG_EXTENDER
+HB_OT_MATH_SCRIPT
hb_ot_layout_table_choose_script
hb_ot_layout_table_find_script
hb_ot_tag_from_language
@@ -224,8 +259,6 @@ hb_coretext_font_get_ct_font
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_get_font_face
-<SUBSECTION Private>
-hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>
@@ -234,27 +267,28 @@ hb_face_count
hb_face_t
hb_face_create
hb_face_create_for_tables
-hb_face_destroy
hb_face_get_empty
+hb_face_reference
+hb_face_destroy
+hb_face_set_user_data
+hb_face_get_user_data
+hb_face_make_immutable
+hb_face_is_immutable
hb_face_get_table_tags
+hb_face_set_glyph_count
hb_face_get_glyph_count
+hb_face_set_index
hb_face_get_index
+hb_face_set_upem
hb_face_get_upem
-hb_face_get_user_data
-hb_face_is_immutable
-hb_face_make_immutable
-hb_face_reference
hb_face_reference_blob
hb_face_reference_table
-hb_face_set_glyph_count
-hb_face_set_index
-hb_face_set_upem
-hb_face_set_user_data
hb_face_collect_unicodes
hb_face_collect_variation_selectors
hb_face_collect_variation_unicodes
hb_face_builder_create
hb_face_builder_add_table
+hb_face_builder_sort_tables
</SECTION>
<SECTION>
@@ -262,110 +296,115 @@ hb_face_builder_add_table
hb_font_add_glyph_origin_for_direction
hb_font_create
hb_font_create_sub_font
-hb_font_destroy
-hb_font_funcs_create
-hb_font_funcs_destroy
-hb_font_funcs_get_empty
-hb_font_funcs_get_user_data
-hb_font_funcs_is_immutable
-hb_font_funcs_make_immutable
-hb_font_funcs_reference
-hb_font_funcs_set_glyph_contour_point_func
-hb_font_funcs_set_glyph_extents_func
-hb_font_funcs_set_glyph_from_name_func
-hb_font_funcs_set_glyph_h_advance_func
-hb_font_funcs_set_glyph_h_advances_func
-hb_font_funcs_set_glyph_h_kerning_func
-hb_font_funcs_set_glyph_h_origin_func
-hb_font_funcs_set_glyph_name_func
-hb_font_funcs_set_glyph_v_advance_func
-hb_font_funcs_set_glyph_v_advances_func
-hb_font_funcs_set_glyph_v_origin_func
-hb_font_funcs_set_nominal_glyph_func
-hb_font_funcs_set_nominal_glyphs_func
-hb_font_funcs_set_user_data
-hb_font_funcs_set_variation_glyph_func
-hb_font_funcs_t
hb_font_get_empty
+hb_font_reference
+hb_font_destroy
+hb_font_set_user_data
+hb_font_get_user_data
+hb_font_make_immutable
+hb_font_is_immutable
+hb_font_set_face
hb_font_get_face
hb_font_get_glyph
hb_font_get_glyph_advance_for_direction
-hb_font_get_glyph_advance_func_t
hb_font_get_glyph_advances_for_direction
-hb_font_get_glyph_advances_func_t
hb_font_get_glyph_contour_point
hb_font_get_glyph_contour_point_for_origin
-hb_font_get_glyph_contour_point_func_t
hb_font_get_glyph_extents
hb_font_get_glyph_extents_for_origin
-hb_font_get_glyph_extents_func_t
hb_font_get_glyph_from_name
-hb_font_get_glyph_from_name_func_t
hb_font_get_glyph_h_advance
-hb_font_get_glyph_h_advance_func_t
+hb_font_get_glyph_v_advance
hb_font_get_glyph_h_advances
-hb_font_get_glyph_h_advances_func_t
+hb_font_get_glyph_v_advances
hb_font_get_glyph_h_kerning
-hb_font_get_glyph_h_kerning_func_t
-hb_font_get_glyph_h_origin
-hb_font_get_glyph_h_origin_func_t
hb_font_get_glyph_kerning_for_direction
-hb_font_get_glyph_kerning_func_t
-hb_font_get_glyph_name
-hb_font_get_glyph_name_func_t
-hb_font_get_glyph_origin_for_direction
-hb_font_get_glyph_origin_func_t
-hb_font_get_glyph_v_advance
-hb_font_get_glyph_v_advance_func_t
-hb_font_get_glyph_v_advances
-hb_font_get_glyph_v_advances_func_t
+hb_font_get_glyph_h_origin
hb_font_get_glyph_v_origin
-hb_font_get_glyph_v_origin_func_t
+hb_font_get_glyph_origin_for_direction
+hb_font_get_glyph_name
+hb_font_get_glyph_shape
hb_font_get_nominal_glyph
-hb_font_get_nominal_glyph_func_t
hb_font_get_nominal_glyphs
-hb_font_get_nominal_glyphs_func_t
+hb_font_get_variation_glyph
+hb_font_set_parent
hb_font_get_parent
+hb_font_set_ppem
hb_font_get_ppem
+hb_font_set_ptem
hb_font_get_ptem
+hb_font_set_scale
hb_font_get_scale
-hb_font_get_user_data
-hb_font_get_variation_glyph
-hb_font_get_variation_glyph_func_t
+hb_font_set_synthetic_slant
+hb_font_get_synthetic_slant
+hb_font_set_variations
+hb_font_set_var_named_instance
+hb_font_set_var_coords_design
+hb_font_get_var_coords_design
+hb_font_set_var_coords_normalized
hb_font_get_var_coords_normalized
hb_font_glyph_from_string
hb_font_glyph_to_string
-hb_font_is_immutable
-hb_font_make_immutable
-hb_font_reference
-hb_font_set_face
+hb_font_get_serial
+hb_font_changed
hb_font_set_funcs
hb_font_set_funcs_data
-hb_font_set_parent
-hb_font_set_ppem
-hb_font_set_ptem
-hb_font_set_scale
-hb_font_set_user_data
-hb_font_set_variations
-hb_font_set_var_coords_design
-hb_font_set_var_coords_normalized
-hb_font_set_var_named_instance
hb_font_subtract_glyph_origin_for_direction
+hb_font_funcs_create
+hb_font_funcs_get_empty
+hb_font_funcs_reference
+hb_font_funcs_destroy
+hb_font_funcs_set_user_data
+hb_font_funcs_get_user_data
+hb_font_funcs_make_immutable
+hb_font_funcs_is_immutable
+hb_font_get_glyph_contour_point_func_t
+hb_font_funcs_set_glyph_contour_point_func
+hb_font_get_glyph_extents_func_t
+hb_font_funcs_set_glyph_extents_func
+hb_font_get_glyph_from_name_func_t
+hb_font_funcs_set_glyph_from_name_func
+hb_font_get_glyph_advance_func_t
+hb_font_get_glyph_h_advance_func_t
+hb_font_funcs_set_glyph_h_advance_func
+hb_font_get_glyph_v_advance_func_t
+hb_font_funcs_set_glyph_v_advance_func
+hb_font_get_glyph_advances_func_t
+hb_font_get_glyph_h_advances_func_t
+hb_font_funcs_set_glyph_h_advances_func
+hb_font_get_glyph_v_advances_func_t
+hb_font_funcs_set_glyph_v_advances_func
+hb_font_get_glyph_kerning_func_t
+hb_font_get_glyph_h_kerning_func_t
+hb_font_funcs_set_glyph_h_kerning_func
+hb_font_get_glyph_origin_func_t
+hb_font_get_glyph_h_origin_func_t
+hb_font_funcs_set_glyph_h_origin_func
+hb_font_get_glyph_v_origin_func_t
+hb_font_funcs_set_glyph_v_origin_func
+hb_font_get_glyph_name_func_t
+hb_font_funcs_set_glyph_name_func
+hb_font_get_glyph_shape_func_t
+hb_font_funcs_set_glyph_shape_func
+hb_font_get_nominal_glyph_func_t
+hb_font_funcs_set_nominal_glyph_func
+hb_font_get_nominal_glyphs_func_t
+hb_font_funcs_set_nominal_glyphs_func
+hb_font_get_variation_glyph_func_t
+hb_font_funcs_set_variation_glyph_func
+hb_font_funcs_t
hb_font_t
hb_reference_table_func_t
-hb_font_funcs_set_font_h_extents_func
-hb_font_funcs_set_font_v_extents_func
-hb_font_get_extents_for_direction
hb_font_get_font_extents_func_t
hb_font_get_font_h_extents_func_t
+hb_font_funcs_set_font_h_extents_func
hb_font_get_font_v_extents_func_t
+hb_font_funcs_set_font_v_extents_func
hb_font_get_h_extents
hb_font_get_v_extents
+hb_font_get_extents_for_direction
hb_font_extents_t
hb_glyph_extents_t
-<SUBSECTION Private>
-hb_font_get_var_coords_design
-hb_font_draw_glyph
</SECTION>
<SECTION>
@@ -382,6 +421,7 @@ hb_ft_font_unlock_face
hb_ft_font_set_load_flags
hb_ft_font_get_load_flags
hb_ft_font_set_funcs
+hb_ft_hb_font_changed
</SECTION>
<SECTION>
@@ -413,27 +453,29 @@ hb_icu_script_to_script
<SECTION>
<FILE>hb-map</FILE>
-HB_MAP_VALUE_INVALID
+hb_map_create
hb_map_allocation_successful
+hb_map_copy
hb_map_clear
-hb_map_create
-hb_map_del
-hb_map_destroy
-hb_map_get
hb_map_get_empty
-hb_map_get_population
+hb_map_reference
+hb_map_destroy
+hb_map_set_user_data
hb_map_get_user_data
+hb_map_set
+hb_map_get
+hb_map_del
hb_map_has
+hb_map_get_population
hb_map_is_empty
-hb_map_reference
-hb_map_set
-hb_map_set_user_data
+hb_map_is_equal
+hb_map_hash
+HB_MAP_VALUE_INVALID
hb_map_t
</SECTION>
<SECTION>
<FILE>hb-ot-color</FILE>
-hb_color_t
HB_COLOR
hb_color_get_alpha
hb_color_get_blue
@@ -446,13 +488,14 @@ hb_ot_color_has_layers
hb_ot_color_has_palettes
hb_ot_color_has_png
hb_ot_color_has_svg
-hb_ot_color_layer_t
hb_ot_color_palette_color_get_name_id
-hb_ot_color_palette_flags_t
hb_ot_color_palette_get_colors
hb_ot_color_palette_get_count
hb_ot_color_palette_get_flags
hb_ot_color_palette_get_name_id
+hb_color_t
+hb_ot_color_layer_t
+hb_ot_color_palette_flags_t
</SECTION>
<SECTION>
@@ -462,35 +505,21 @@ hb_ot_font_set_funcs
<SECTION>
<FILE>hb-ot-name</FILE>
-hb_ot_name_id_t
-HB_OT_NAME_ID_INVALID
-hb_ot_name_entry_t
hb_ot_name_list_names
hb_ot_name_get_utf16
hb_ot_name_get_utf32
hb_ot_name_get_utf8
+HB_OT_NAME_ID_INVALID
+hb_ot_name_id_t
+hb_ot_name_entry_t
</SECTION>
<SECTION>
<FILE>hb-ot-layout</FILE>
-HB_OT_MAX_TAGS_PER_LANGUAGE
-HB_OT_MAX_TAGS_PER_SCRIPT
-HB_OT_TAG_DEFAULT_LANGUAGE
-HB_OT_TAG_DEFAULT_SCRIPT
hb_ot_tag_to_language
hb_ot_tag_to_script
hb_ot_tags_from_script_and_language
hb_ot_tags_to_script_and_language
-HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
-HB_OT_LAYOUT_NO_FEATURE_INDEX
-HB_OT_LAYOUT_NO_SCRIPT_INDEX
-HB_OT_LAYOUT_NO_VARIATIONS_INDEX
-HB_OT_TAG_BASE
-HB_OT_TAG_GDEF
-HB_OT_TAG_GPOS
-HB_OT_TAG_GSUB
-HB_OT_TAG_JSTF
-hb_ot_layout_baseline_tag_t
hb_ot_layout_collect_lookups
hb_ot_layout_collect_features
hb_ot_layout_feature_get_characters
@@ -498,12 +527,13 @@ hb_ot_layout_feature_get_lookups
hb_ot_layout_feature_get_name_ids
hb_ot_layout_feature_with_variations_get_lookups
hb_ot_layout_get_attach_points
+hb_ot_layout_get_horizontal_baseline_tag_for_script
hb_ot_layout_get_baseline
+hb_ot_layout_get_baseline_with_fallback
hb_ot_layout_get_glyph_class
hb_ot_layout_get_glyphs_in_class
hb_ot_layout_get_ligature_carets
hb_ot_layout_get_size_params
-hb_ot_layout_glyph_class_t
hb_ot_layout_has_glyph_classes
hb_ot_layout_has_positioning
hb_ot_layout_has_substitution
@@ -513,6 +543,7 @@ hb_ot_layout_language_get_feature_tags
hb_ot_layout_language_get_required_feature
hb_ot_layout_lookup_collect_glyphs
hb_ot_layout_lookup_get_glyph_alternates
+hb_ot_layout_lookup_get_optical_bound
hb_ot_layout_lookup_substitute_closure
hb_ot_layout_lookups_substitute_closure
hb_ot_layout_lookup_would_substitute
@@ -526,48 +557,60 @@ hb_ot_layout_table_get_lookup_count
hb_ot_layout_table_select_script
hb_ot_shape_plan_collect_lookups
hb_ot_layout_language_get_required_feature_index
-<SUBSECTION Private>
-Xhb_ot_layout_lookup_enumerate_sequences
-Xhb_ot_layout_lookup_position
-Xhb_ot_layout_lookup_substitute
-hb_ot_layout_glyph_sequence_t
-hb_ot_layout_glyph_sequence_func_t
+HB_OT_MAX_TAGS_PER_LANGUAGE
+HB_OT_MAX_TAGS_PER_SCRIPT
+HB_OT_TAG_DEFAULT_LANGUAGE
+HB_OT_TAG_DEFAULT_SCRIPT
+HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
+HB_OT_LAYOUT_NO_FEATURE_INDEX
+HB_OT_LAYOUT_NO_SCRIPT_INDEX
+HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+HB_OT_TAG_BASE
+HB_OT_TAG_GDEF
+HB_OT_TAG_GPOS
+HB_OT_TAG_GSUB
+HB_OT_TAG_JSTF
+hb_ot_layout_baseline_tag_t
+hb_ot_layout_glyph_class_t
</SECTION>
<SECTION>
<FILE>hb-ot-math</FILE>
-HB_OT_TAG_MATH
-HB_OT_MATH_SCRIPT
-hb_ot_math_constant_t
-hb_ot_math_kern_t
-hb_ot_math_glyph_variant_t
-hb_ot_math_glyph_part_flags_t
-hb_ot_math_glyph_part_t
hb_ot_math_has_data
hb_ot_math_get_constant
hb_ot_math_get_glyph_italics_correction
hb_ot_math_get_glyph_top_accent_attachment
hb_ot_math_get_glyph_kerning
+hb_ot_math_get_glyph_kernings
hb_ot_math_is_glyph_extended_shape
hb_ot_math_get_glyph_variants
hb_ot_math_get_min_connector_overlap
hb_ot_math_get_glyph_assembly
+HB_OT_TAG_MATH
+HB_OT_TAG_MATH_SCRIPT
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_kern_entry_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
</SECTION>
<SECTION>
<FILE>hb-ot-meta</FILE>
-hb_ot_meta_tag_t
hb_ot_meta_get_entry_tags
hb_ot_meta_reference_entry
+hb_ot_meta_tag_t
</SECTION>
<SECTION>
<FILE>hb-ot-metrics</FILE>
-hb_ot_metrics_tag_t
hb_ot_metrics_get_position
+hb_ot_metrics_get_position_with_fallback
hb_ot_metrics_get_variation
hb_ot_metrics_get_x_variation
hb_ot_metrics_get_y_variation
+hb_ot_metrics_tag_t
</SECTION>
<SECTION>
@@ -577,14 +620,7 @@ hb_ot_shape_glyphs_closure
<SECTION>
<FILE>hb-ot-var</FILE>
-HB_OT_TAG_VAR_AXIS_ITALIC
-HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
-HB_OT_TAG_VAR_AXIS_SLANT
-HB_OT_TAG_VAR_AXIS_WEIGHT
-HB_OT_TAG_VAR_AXIS_WIDTH
hb_ot_var_has_data
-hb_ot_var_axis_flags_t
-hb_ot_var_axis_info_t
hb_ot_var_find_axis_info
hb_ot_var_get_axis_count
hb_ot_var_get_axis_infos
@@ -594,42 +630,52 @@ hb_ot_var_named_instance_get_postscript_name_id
hb_ot_var_named_instance_get_design_coords
hb_ot_var_normalize_variations
hb_ot_var_normalize_coords
+HB_OT_TAG_VAR_AXIS_ITALIC
+HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
+HB_OT_TAG_VAR_AXIS_SLANT
+HB_OT_TAG_VAR_AXIS_WEIGHT
+HB_OT_TAG_VAR_AXIS_WIDTH
+hb_ot_var_axis_flags_t
+hb_ot_var_axis_info_t
</SECTION>
<SECTION>
<FILE>hb-set</FILE>
-HB_SET_VALUE_INVALID
-hb_set_add
-hb_set_add_range
+hb_set_create
hb_set_allocation_successful
hb_set_copy
+hb_set_get_empty
+hb_set_reference
+hb_set_destroy
+hb_set_set_user_data
+hb_set_get_user_data
hb_set_clear
-hb_set_create
+hb_set_set
+hb_set_has
+hb_set_add
+hb_set_add_range
+hb_set_add_sorted_array
hb_set_del
hb_set_del_range
-hb_set_destroy
-hb_set_get_empty
hb_set_get_max
hb_set_get_min
hb_set_get_population
-hb_set_get_user_data
-hb_set_has
+hb_set_is_empty
+hb_set_hash
+hb_set_subtract
hb_set_intersect
+hb_set_union
+hb_set_symmetric_difference
hb_set_invert
-hb_set_is_empty
hb_set_is_equal
hb_set_is_subset
hb_set_next
hb_set_next_range
+hb_set_next_many
hb_set_previous
hb_set_previous_range
-hb_set_reference
-hb_set_set
-hb_set_set_user_data
-hb_set_subtract
-hb_set_symmetric_difference
+HB_SET_VALUE_INVALID
hb_set_t
-hb_set_union
</SECTION>
<SECTION>
@@ -645,50 +691,50 @@ hb_shape_plan_create
hb_shape_plan_create_cached
hb_shape_plan_create2
hb_shape_plan_create_cached2
-hb_shape_plan_destroy
-hb_shape_plan_execute
hb_shape_plan_get_empty
-hb_shape_plan_get_shaper
-hb_shape_plan_get_user_data
hb_shape_plan_reference
+hb_shape_plan_destroy
hb_shape_plan_set_user_data
+hb_shape_plan_get_user_data
+hb_shape_plan_execute
+hb_shape_plan_get_shaper
hb_shape_plan_t
</SECTION>
<SECTION>
<FILE>hb-unicode</FILE>
-HB_UNICODE_MAX
+hb_unicode_general_category
hb_unicode_combining_class
-hb_unicode_combining_class_func_t
-hb_unicode_combining_class_t
+hb_unicode_mirroring
+hb_unicode_script
hb_unicode_compose
-hb_unicode_compose_func_t
hb_unicode_decompose
-hb_unicode_decompose_func_t
hb_unicode_funcs_create
-hb_unicode_funcs_destroy
-hb_unicode_funcs_get_default
hb_unicode_funcs_get_empty
-hb_unicode_funcs_get_parent
+hb_unicode_funcs_reference
+hb_unicode_funcs_destroy
+hb_unicode_funcs_set_user_data
hb_unicode_funcs_get_user_data
-hb_unicode_funcs_is_immutable
hb_unicode_funcs_make_immutable
-hb_unicode_funcs_reference
-hb_unicode_funcs_set_combining_class_func
-hb_unicode_funcs_set_compose_func
-hb_unicode_funcs_set_decompose_func
+hb_unicode_funcs_is_immutable
+hb_unicode_funcs_get_default
+hb_unicode_funcs_get_parent
+hb_unicode_general_category_func_t
hb_unicode_funcs_set_general_category_func
+hb_unicode_combining_class_func_t
+hb_unicode_funcs_set_combining_class_func
+hb_unicode_mirroring_func_t
hb_unicode_funcs_set_mirroring_func
+hb_unicode_script_func_t
hb_unicode_funcs_set_script_func
-hb_unicode_funcs_set_user_data
-hb_unicode_funcs_t
-hb_unicode_general_category
-hb_unicode_general_category_func_t
+hb_unicode_compose_func_t
+hb_unicode_funcs_set_compose_func
+hb_unicode_decompose_func_t
+hb_unicode_funcs_set_decompose_func
+HB_UNICODE_MAX
+hb_unicode_combining_class_t
hb_unicode_general_category_t
-hb_unicode_mirroring
-hb_unicode_mirroring_func_t
-hb_unicode_script
-hb_unicode_script_func_t
+hb_unicode_funcs_t
</SECTION>
<SECTION>
@@ -700,13 +746,13 @@ hb_uniscribe_font_get_logfontw
<SECTION>
<FILE>hb-version</FILE>
HB_VERSION_ATLEAST
+hb_version
+hb_version_atleast
+hb_version_string
HB_VERSION_MAJOR
HB_VERSION_MICRO
HB_VERSION_MINOR
HB_VERSION_STRING
-hb_version
-hb_version_atleast
-hb_version_string
</SECTION>
<SECTION>
@@ -717,18 +763,36 @@ hb_style_get_value
<SECTION>
<FILE>hb-subset</FILE>
-hb_subset_flags_t
-hb_subset_input_t
-hb_subset_sets_t
hb_subset_input_create_or_fail
hb_subset_input_reference
hb_subset_input_destroy
hb_subset_input_set_user_data
hb_subset_input_get_user_data
-hb_subset_input_get_flags
hb_subset_input_set_flags
+hb_subset_input_get_flags
hb_subset_input_unicode_set
hb_subset_input_glyph_set
hb_subset_input_set
+hb_subset_input_pin_axis_location
+hb_subset_input_pin_axis_to_default
hb_subset_or_fail
+hb_subset_plan_create_or_fail
+hb_subset_plan_reference
+hb_subset_plan_destroy
+hb_subset_plan_set_user_data
+hb_subset_plan_get_user_data
+hb_subset_plan_execute_or_fail
+hb_subset_plan_unicode_to_old_glyph_mapping
+hb_subset_plan_new_to_old_glyph_mapping
+hb_subset_plan_old_to_new_glyph_mapping
+hb_subset_preprocess
+hb_subset_flags_t
+hb_subset_input_t
+hb_subset_sets_t
+hb_subset_plan_t
+<SUBSECTION Private>
+hb_link_t
+hb_object_t
+hb_subset_repack_or_fail
+hb_subset_input_override_name_table
</SECTION>
diff --git a/docs/meson.build b/docs/meson.build
index 73d9521fd..9da1fd564 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -49,8 +49,8 @@ ignore_headers = [
gnome.gtkdoc('harfbuzz',
main_sgml: 'harfbuzz-docs.xml',
- src_dir: [join_paths(meson.current_source_dir(), '../src'),
- join_paths(meson.current_build_dir(), '../src'),
+ src_dir: [meson.current_source_dir() / '..' / 'src',
+ meson.current_build_dir() / '..' / 'src',
],
scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
'--ignore-decorators=HB_EXTERN|HB_DEPRECATED',
diff --git a/docs/repacker.md b/docs/repacker.md
index b7aacc455..397ce4fa6 100644
--- a/docs/repacker.md
+++ b/docs/repacker.md
@@ -23,11 +23,11 @@ Offset overflows can happen for a variety of reasons and require different strat
for more flexibility in the ordering.
* In GSUB/GPOS overflows from Lookup subtables can be resolved by changing the Lookup to an extension
lookup which uses a 32 bit offset instead of 16 bit offset.
-
+
In general there isn't a simple solution to produce an optimal topological ordering for a given graph.
Finding an ordering which doesn't overflow is a NP hard problem. Existing solutions use heuristics
which attempt a combination of the above strategies to attempt to find a non-overflowing configuration.
-
+
The harfbuzz subsetting library
[includes a repacking algorithm](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh)
which is used to resolve offset overflows that are present in the subsetted tables it produces. This
@@ -40,23 +40,29 @@ Other implementations exist, such as in
There's four key pieces to the harfbuzz approach:
-* Subtable Graph: a table's internal structure is abstraced out into a lightweight graph
+* Subtable Graph: a table's internal structure is abstracted out into a lightweight graph
representation where each subtable is a node and each offset forms an edge. The nodes only need
to know how many bytes the corresponding subtable occupies. This lightweight representation can
be easily modified to test new ordering's and strategies as the repacking algorithm iterates.
* [Topological sorting algorithm](https://en.wikipedia.org/wiki/Topological_sorting): an algorithm
which given a graph gives a linear sorting of the nodes such that all offsets will be positive.
-
+
* Overflow check: given a graph and a topological sorting it checks if there will be any overflows
in any of the offsets. If there are overflows it returns a list of (parent, child) tuples that
will overflow. Since the graph has information on the size of each subtable it's straightforward
to calculate the final position of each subtable and then check if any offsets to it will
overflow.
-
-* Offset resolution strategies: given a particular occurence of an overflow these strategies
+
+* Content Aware Preprocessing: if the overflow resolver is aware of the format of the underlying
+ tables (eg. GSUB, GPOS) then in some cases preprocessing can be done to increase the chance of
+ successfully packing the graph. For example for GSUB and GPOS we can preprocess the graph and
+ promote lookups to extension lookups (upgrades a 16 bit offset to 32 bits) or split large lookup
+ subtables into two or more pieces.
+
+* Offset resolution strategies: given a particular occurrence of an overflow these strategies
modify the graph to attempt to resolve the overflow.
-
+
# High Level Algorithm
```
@@ -64,6 +70,7 @@ def repack(graph):
graph.topological_sort()
if (graph.will_overflow())
+ preprocess(graph)
assign_spaces(graph)
graph.topological_sort()
@@ -85,7 +92,7 @@ The harfbuzz repacker uses two different algorithms for topological sorting:
Kahn's algorithm is approximately twice as fast as the shortest distance sort so that is attempted
first (only on the first topological sort). If it fails to eliminate overflows then shortest distance
sort will be used for all subsequent topological sorting operations.
-
+
## Shortest Distance Sort
This algorithm orders the nodes based on total distance to each node. Nodes with a shorter distance
@@ -111,9 +118,9 @@ to be as fast as possible. There's a few things that are done to speed up subseq
operations:
* The number of incoming edges to each node is cached. This is required by the Kahn's algorithm
- portion of boths sorts. Where possible when the graph is modified we manually update the cached
+ portion of both sorts. Where possible when the graph is modified we manually update the cached
edge counts of affected nodes.
-
+
* The distance to each node is cached. Where possible when the graph is modified we manually update
the cached distances of any affected nodes.
@@ -165,7 +172,7 @@ The above is an ideal situation where the subgraphs are disconnected from each o
this is often not this case. So this idea can be generalized as follows:
If there is a subgraph that is only reachable from one or more 32 bit offsets, then:
-* That subgraph can be treated as an indepedent unit and all nodes of the subgraph packed in isolation
+* That subgraph can be treated as an independent unit and all nodes of the subgraph packed in isolation
from the rest of the graph.
* In a table that occupies less than 4gb of space (in practice all fonts), that packed independent
subgraph can be placed anywhere after the parent nodes without overflowing the 32 bit offsets from
@@ -185,6 +192,37 @@ The assign_spaces() step in the high level algorithm is responsible for identify
subgraphs and assigning unique spaces to each one. More information on the space assignment can be
found in the next section.
+# Graph Preprocessing
+
+For certain table types we can preprocess and modify the graph structure to reduce the occurences
+of overflows. Currently the repacker implements preprocessing only for GPOS and GSUB tables.
+
+## GSUB/GPOS Table Splitting
+
+The GSUB/GPOS preprocessor scans each lookup subtable and determines if the subtable's children are
+so large that no overflow resolution is possible (for example a single subtable that exceeds 65kb
+cannot be pointed over). When such cases are detected table splitting is invoked:
+
+* The subtable is first analyzed to determine the smallest number of split points that will allow
+ for successful offset overflow resolution.
+
+* Then the subtable in the graph representation is modified to actually perform the split at the
+ previously computed split points. At a high level splits are done by inserting new subtables
+ which contain a subset of the data of the original subtable and then shrinking the original subtable.
+
+Table splitting must be aware of the underlying format of each subtable type and thus needs custom
+code for each subtable type. Currently subtable splitting is only supported for GPOS subtable types.
+
+## GSUB/GPOS Extension Lookup Promotion
+
+In GSUB/GPOS tables lookups can be regular lookups which use 16 bit offsets to the children subtables
+or extension lookups which use 32 bit offsets to the children subtables. If the sub graph of all
+regular lookups is too large then it can be difficult to find an overflow free configuration. This
+can be remedied by promoting one or more regular lookups to extension lookups.
+
+During preprocessing the graph is scanned to determine the size of the subgraph of regular lookups.
+If the graph is found to be too big then the analysis finds a set of lookups to promote to reduce
+the subgraph size. Lastly the graph is modified to convert those lookups to extension lookups.
# Offset Resolution Strategies
@@ -204,20 +242,20 @@ and then assign each such subgraph to a unique non-zero space. The algorithm is
a. Pick a node `n` in set `S` then perform an undirected graph traversal and find the set `Q` of
nodes that are reachable from `n`.
-
+
b. During traversal if a node, `m`, has a edge to a node in space 0 then `m` must be duplicated
to disconnect it from space 0.
-
+
d. Remove all nodes in `Q` from `S` and assign all nodes in `Q` to `next_space`.
-
-
+
+
c. Increment `next_space` by one.
## Manual Iterative Resolutions
For each overflow in each iteration the algorithm will attempt to apply offset overflow resolution
-strategies to eliminate the overflow. The type of strategy applied is dependant on the characteristics
+strategies to eliminate the overflow. The type of strategy applied is dependent on the characteristics
of the overflowing link:
* If the overflowing offset is inside a space other than space 0 and the subgraph space has more
@@ -226,40 +264,31 @@ of the overflowing link:
* If the overflowing offset is pointing to a subtable with more than one incoming edge: duplicate
the node so that the overflowing offset is pointing at it's own copy of that node.
-
+
* Otherwise, attempt to move the child subtable closer to it's parent. This is accomplished by
raising the priority of all children of the parent. Next time the topological sort is run the
children will be ordered closer to the parent.
-
+
# Test Cases
The harfbuzz repacker has tests defined using generic graphs: https://github.com/harfbuzz/harfbuzz/blob/main/src/test-repacker.cc
-
-# Future Improvments
-The above resolution strategies are not sufficient to resolve all overflows. For example consider
-the case where a single subtable is 65k and the graph structure requires an offset to point over it.
+# Future Improvements
+
+Currently for GPOS tables the repacker implementation is sufficient to handle both subsetting and the
+general case of font compilation repacking. However for GSUB the repacker is only sufficient for
+subsetting related overflows. To enable general case repacking of GSUB, support for splitting of
+GSUB subtables will need to be added. Other table types such as COLRv1 shouldn't require table
+splitting due to the wide use of 24 bit offsets throughout the table.
+
+Beyond subtable splitting there are a couple of "nice to have" improvements, but these are not required
+to support the general case:
-The current harfbuzz implementation is suitable for the vast majority of subsetting related overflows.
-Subsetting related overflows are typically easy to solve since all subsets are derived from a font
-that was originally overflow free. A more general purpose version of the algorithm suitable for font
-creation purposes will likely need some additional offset resolution strategies:
+* Extension demotion: currently extension promotion is supported but in some cases if the non-extension
+ subgraph is underfilled then packed size can be reduced by demoting extension lookups back to regular
+ lookups.
* Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
should use a heuristic (based on parent and child subtable sizes) to decide if the children's
priority should be increased or the parent's priority decreased.
-
-* Many subtables can be split into two smaller subtables without impacting the overall functionality.
- This should be done when an overflow is the result of a very large table which can't be moved
- to avoid offsets pointing over it.
-
-* Lookup subtables in GSUB/GPOS can be upgraded to extension lookups which uses a 32 bit offset.
- Overflows from a Lookup subtable to it's child should be resolved by converting to an extension
- lookup.
-
-Once additional resolution strategies are added to the algorithm it's likely that we'll need to
-switch to using a [backtracking algorithm](https://en.wikipedia.org/wiki/Backtracking) to explore
-the various combinations of resolution strategies until a non-overflowing combination is found. This
-will require the ability to restore the graph to an earlier state. It's likely that using a stack
-of undoable resolution commands could be used to accomplish this.
diff --git a/docs/serializer.md b/docs/serializer.md
new file mode 100644
index 000000000..0efda8055
--- /dev/null
+++ b/docs/serializer.md
@@ -0,0 +1,178 @@
+# Introduction
+
+In hb-subset serialization is the process of writing the subsetted font
+tables out to actual bytes in the final format. All serialization works
+through an object called the serialize context
+([hb_serialize_context_t](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-serialize.hh)).
+
+Internally the serialize context holds a fixed size memory buffer. For simple
+tables the final bytes are written into the buffer sequentially to produce
+the final serialized bytes.
+
+## Simple Tables
+
+Simple tables are tables that do not use offset graphs.
+
+To write a struct into the serialization context, first you call an
+allocation method on the context which requests a writable array of bytes of
+a fixed size. If the requested array will not exceed the bounds of the fixed
+buffer the serializer will return a pointer to the next unwritten portion
+of the buffer. Then the struct is cast onto the returned pointer and values
+are written to the structs fields.
+
+Internally the serialization context ends up looking like:
+
+```
++-------+-------+-----+-------+--------------+
+| Obj 1 | Obj 2 | ... | Obj N | Unused Space |
++-------+-------+-----+-------+--------------+
+```
+
+Here Obj N, is the object currently being written.
+
+## Complex Tables
+
+Complex tables are made up of graphs of objects, where offset's are used
+to form the edges of the graphs. Each object is a continuous slice of bytes
+that contains zero or more offsets pointing to more objects.
+
+In this case the serialization buffer has a different layout:
+
+```
+|- in progress objects -| |--- packed objects --|
++-----------+-----------+--------------+-------+-----+-------+
+| Obj n+2 | Obj n+1 | Unused Space | Obj n | ... | Obj 0 |
++-----------+-----------+--------------+-------+-----+-------+
+|-----------------------> <---------------------|
+```
+
+The buffer holds two stacks:
+
+1. In progress objects are held in a stack starting from the start of buffer
+ that grows towards the end of the buffer.
+
+2. Packed objects are held in a stack that starts at the end of the buffer
+ and grows towards the start of the buffer.
+
+Once the object on the top of the in progress stack is finished being written
+its bytes are popped from the in progress stack and copied to the top of
+the packed objects stack. In the example above, finalizing Obj n+1
+would result in the following state:
+
+```
++---------+--------------+---------+-------+-----+-------+
+| Obj n+2 | Unused Space | Obj n+1 | Obj n | ... | Obj 0 |
++---------+--------------+---------+-------+-----+-------+
+```
+
+Each packed object is associated with an ID, it's zero based position in the packed
+objects stack. In this example Obj 0, would have an ID of 0.
+
+During serialization offsets that link from one object to another are stored
+using object ids. The serialize context maintains a list of links between
+objects. Each link records the parent object id, the child object id, the position
+of the offset field within the parent object, and the width of the offset.
+
+Links are always added to the current in progress object and you can only link too
+objects that have been packed and thus have an ID.
+
+### Object De-duplication
+
+An important optimization in packing offset graphs is de-duplicating equivalent objects. If you
+have two or more parent objects that point to child objects that are equivalent then you only need
+to encode the child once and can have the parents point to the same child. This can significantly
+reduce the final size of a serialized graph.
+
+During packing of an inprogress object the serialization context checks if any existing packed
+objects are equivalent to the object being packed. Here equivalence means the object has the
+exact same bytes and all of it's links are equivalent. If an equivalent object is found the
+in progress object is discarded and not copied to the packed object stack. The object id of
+the equivalent object is instead returned. Thus parent objects will then link to the existing
+equivalent object.
+
+To find equivalent objects the serialization context maintains a hashmap from object to the canonical
+object id.
+
+### Link Resolution
+
+Once all objects have been packed the next step is to assign actual values to all of the offset
+fields. Prior to this point all links in the graph have been recorded using object id's. For each
+link the resolver computes the offset between the parent and child and writes the offset into
+the serialization buffer at the appropriate location.
+
+### Offset Overflow Resolution
+
+If during link resolution the resolver finds that an offsets value would exceed what can be encoded
+in that offset field link resolution is aborted and the offset overflow resolver is invoked.
+That process is documented [here](reapcker.md).
+
+
+### Example of Complex Serialization
+
+
+If we wanted to serialize the following graph:
+
+```
+a--b--d
+ \ /
+ c
+```
+
+Serializer would be called like this:
+
+```c++
+hb_serialize_context_t ctx;
+
+struct root {
+ char name;
+ Offset16To<child> child_1;
+ Offset16To<child> child_2;
+}
+
+struct child {
+ char name;
+ Offset16To<char> leaf;
+}
+
+// Object A.
+ctx->push();
+root* a = ctx->start_embed<root> ();
+ctx->extend_min (a);
+a->name = 'a';
+
+// Object B.
+ctx->push();
+child* b = ctx->start_embed<child> ();
+ctx->extend_min (b);
+b->name = 'b';
+
+// Object D.
+ctx->push();
+*ctx->allocate_size<char> (1) = 'd';
+unsigned d_id = ctx->pop_pack ();
+
+ctx->add_link (b->leaf, d_id);
+unsigned b_id = ctx->pop_pack ();
+
+// Object C
+ctx->push();
+child* c = ctx->start_embed<child> ();
+ctx->extend_min (c);
+c->name = 'c';
+
+// Object D.
+ctx->push();
+*ctx->allocate_size<char> (1) = 'd';
+d_id = ctx->pop_pack (); // Serializer will automatically de-dup this with the previous 'd'
+
+ctx->add_link (c->leaf, d_id);
+unsigned c_id = ctx->pop_pack ();
+
+// Object A's links:
+ctx->add_link (a->child_1, b_id);
+ctx->add_link (a->child_2, c_id);
+ctx->pop_pack ();
+
+ctx->end_serialize ();
+
+```
diff --git a/docs/subset-preprocessing.md b/docs/subset-preprocessing.md
new file mode 100644
index 000000000..637da2865
--- /dev/null
+++ b/docs/subset-preprocessing.md
@@ -0,0 +1,228 @@
+# Introduction
+
+Subset preprocessing is a mechanism which can significantly speed up font subsetting operations.
+It works by prepopulating datastructures from the source font which can be used in later subsetting
+operations to more quickly produce the subset. Preprocessing is useful in cases where multiple subsets
+will be cut from the same source font.
+
+# Usage
+
+```c++
+hb_face_t* preprocessed = hb_subset_preprocess (source_face);
+
+...
+
+hb_face_t* subset = hb_subset_or_fail (preprocessed, subset_input);
+```
+
+# Additional Details
+
+* A subset produced from a preprocessed face should be identical to a subset produced from only the
+ original face. The preprocessor does not change the functionality of the subsetter, just speeds
+ things up.
+
+* The preprocessing operation may take longer than the time it takes to produce a subset from the
+ source font. Thus the main performance gains are made when a preprocessed face is reused for
+ multiple subsetting operations.
+
+* Currently the largest performance gains are seen when using a preprocessed face for CFF subsetting.
+
+* The preprocessed face may contain references to the memory backing the source face. If this memory
+ is fully owned by a harfbuzz hb_blob_t* then it will automatically be kept alive for the lifetime
+ of the preprocessed face. However, if this memory is not fully owned by a harfbuzz hb_blob_t* then
+ it is necessary to ensure that the memory is kept alive for the lifetime of the preprocessed face.
+
+
+# Performance Improvements
+
+Here is the performance difference of producing a subset with a preprocessed face vs producing
+a subset with the source face:
+
+Benchmark | Delta Time (%)
+----------|-----------------
+BM_subset/subset_glyphs/Roboto-Regular.ttf/10_median|-56%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/64_median|-33%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/512_median|-28%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/1000_median|-11%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/10_median|-56%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/64_median|-33%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/512_median|-21%
+BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/1000_median|-9%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/10_median|-67%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/64_median|-48%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/512_median|-21%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/4096_median|-9%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/10_median|-66%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/64_median|-50%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/512_median|-8%
+BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/4096_median|-9%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/10_median|-85%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/64_median|-71%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/512_median|-3%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1400_median|4%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-84%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-72%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|0%
+BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|0%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/10_median|-30%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/64_median|-24%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/512_median|-3%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/1000_median|-3%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-30%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-3%
+BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|-5%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10_median|-96%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64_median|-90%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512_median|-74%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096_median|-25%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000_median|-23%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10_median|-95%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/64_median|-90%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/512_median|-73%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/4096_median|-24%
+BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10000_median|-11%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10_median|-84%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/64_median|-77%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/512_median|-70%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/4096_median|-80%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000_median|-86%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10_median|-84%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/64_median|-78%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512_median|-71%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
+BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10_median|-59%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64_median|-55%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512_median|-67%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000_median|-68%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/10_median|-60%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/64_median|-58%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/512_median|-72%
+BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/2000_median|-71%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/10_median|-70%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/64_median|-64%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/300_median|-73%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/10_median|-71%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/64_median|-68%
+BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/300_median|-72%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/10_median|-90%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/64_median|-82%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/512_median|-31%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/4096_median|-9%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/6000_median|-22%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/10_median|-88%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/64_median|-83%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/512_median|-31%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/4096_median|-16%
+BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/6000_median|-18%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/10_median|-44%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/64_median|-18%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/512_median|-2%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/900_median|-6%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/10_median|-45%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/64_median|-17%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/512_median|-15%
+BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/900_median|-3%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/10_median|-20%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/64_median|-16%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/512_median|-12%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/1000_median|-10%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10_median|-24%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/64_median|-14%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/512_median|-15%
+BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/1000_median|-9%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/10_median|-51%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/64_median|-37%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/512_median|-12%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/4096_median|-1%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10_median|-49%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/64_median|-35%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/512_median|-6%
+BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/4096_median|-1%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/10_median|-82%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/64_median|-9%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/512_median|0%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1400_median|0%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-82%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-13%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|-3%
+BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|2%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/10_median|-40%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/64_median|-26%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/512_median|-5%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/1000_median|3%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-43%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-2%
+BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|2%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10_median|-83%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/64_median|-67%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/512_median|-39%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/4096_median|-20%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10000_median|-25%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10_median|-83%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/64_median|-65%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/512_median|-42%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/4096_median|-34%
+BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10000_median|-21%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10_median|-69%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/64_median|-69%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/512_median|-70%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096_median|-84%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000_median|-83%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10_median|-71%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64_median|-68%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512_median|-70%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
+BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/10_median|-45%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/64_median|-48%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/512_median|-57%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/2000_median|-66%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10_median|-43%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/64_median|-50%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/512_median|-63%
+BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/2000_median|-72%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/10_median|-69%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/64_median|-66%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/300_median|-74%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10_median|-70%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/64_median|-71%
+BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/300_median|-75%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/10_median|-66%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/64_median|-46%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/512_median|-15%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/4096_median|-5%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/6000_median|-16%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10_median|-66%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/64_median|-45%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/512_median|-14%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/4096_median|-11%
+BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/6000_median|-27%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/10_median|-38%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/64_median|-9%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512_median|-3%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/900_median|-16%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10_median|-39%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/64_median|-12%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/512_median|-4%
+BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/900_median|-2%
+BM_subset/instance/MPLUS1-Variable.ttf/10_median|-68%
+BM_subset/instance/MPLUS1-Variable.ttf/64_median|-45%
+BM_subset/instance/MPLUS1-Variable.ttf/512_median|-18%
+BM_subset/instance/MPLUS1-Variable.ttf/4096_median|-2%
+BM_subset/instance/MPLUS1-Variable.ttf/6000_median|4%
+BM_subset/instance/MPLUS1-Variable.ttf/nohinting/10_median|-69%
+BM_subset/instance/MPLUS1-Variable.ttf/nohinting/64_median|-46%
+BM_subset/instance/MPLUS1-Variable.ttf/nohinting/512_median|-11%
+BM_subset/instance/MPLUS1-Variable.ttf/nohinting/4096_median|4%
+BM_subset/instance/MPLUS1-Variable.ttf/nohinting/6000_median|-5%
+BM_subset/instance/RobotoFlex-Variable.ttf/10_median|-34%
+BM_subset/instance/RobotoFlex-Variable.ttf/64_median|-12%
+BM_subset/instance/RobotoFlex-Variable.ttf/512_median|6%
+BM_subset/instance/RobotoFlex-Variable.ttf/900_median|-6%
+BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/10_median|-33%
+BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/64_median|-11%
+BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/512_median|3%
+BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/900_median|0%
diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml
index 9147ff0a5..4f2825c0b 100644
--- a/docs/usermanual-clusters.xml
+++ b/docs/usermanual-clusters.xml
@@ -419,7 +419,7 @@
<section id="reordering-in-levels-0-and-1">
<title>Reordering in levels 0 and 1</title>
<para>
- Another common operation in the more complex shapers is glyph
+ Another common operation in some shapers is glyph
reordering. In order to maintain a monotonic cluster sequence
when glyph reordering takes place, HarfBuzz merges the clusters
of everything in the reordering sequence.
diff --git a/docs/usermanual-getting-started.xml b/docs/usermanual-getting-started.xml
index e7241a694..eb8c1d728 100644
--- a/docs/usermanual-getting-started.xml
+++ b/docs/usermanual-getting-started.xml
@@ -117,7 +117,7 @@
implements separate shapers for Indic, Arabic, Thai and
Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
Universal Shaping Engine (USE), and a default shaper for
- non-complex scripts.
+ scripts with no script-specific shaping model.
</para>
</listitem>
</varlistentry>
diff --git a/docs/usermanual-integration.xml b/docs/usermanual-integration.xml
index 78c9a0e38..5d31ec268 100644
--- a/docs/usermanual-integration.xml
+++ b/docs/usermanual-integration.xml
@@ -347,7 +347,7 @@
<structname>hb_glyph_position_t</structname> structures.
</para>
<para>
- Your client program only needs to ensure that it coverts
+ Your client program only needs to ensure that it converts
correctly between HarfBuzz's low-level data types (such as
<type>hb_position_t</type>) and Windows's corresponding types
(such as <type>GOFFSET</type> and <type>ABC</type>). Be sure you
@@ -445,7 +445,7 @@
is slightly lower-level than Core Text, provides
<ulink url="https://developer.apple.com/documentation/coregraphics/cgfontref"><type>CGFontRef</type></ulink>, which enables access to typeface
properties, but does not include size information. Core Text's
- <ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analagous to a HarfBuzz font object,
+ <ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analogous to a HarfBuzz font object,
with all of the properties required to render text at a specific
size and configuration.
Consequently, a HarfBuzz <type>hb_font_t</type> font object can
diff --git a/docs/usermanual-object-model.xml b/docs/usermanual-object-model.xml
index 23065bf76..3c71a3690 100644
--- a/docs/usermanual-object-model.xml
+++ b/docs/usermanual-object-model.xml
@@ -12,7 +12,7 @@
HarfBuzz features two kinds of data types: non-opaque,
pass-by-value types and opaque, heap-allocated types. This kind
of separation is common in C libraries that have to provide
- API/ABI compatibility (almost) indefinitely.
+ API/ABI compatibility (almost) indefinitely.
</para>
<para>
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
@@ -32,8 +32,8 @@
possible future members. As such, it’s important to provide
<function>equal()</function>, and <function>hash()</function>
methods for such structs, allowing users of the API do
- effectively deal with the type without having to
- adapt their code to future changes.
+ effectively deal with the type without having to
+ adapt their code to future changes.
</para>
<para>
Important value types provided by HarfBuzz include the structs
@@ -42,7 +42,7 @@
OpenType properties.
</para>
</section>
-
+
<section id="object-model-object-types">
<title>Objects in HarfBuzz</title>
<para>
@@ -63,7 +63,7 @@
the <literal>hb_buffer_t</literal> object has
<function>hb_buffer_create()</function> as its constructor,
<function>hb_buffer_reference()</function> to reference, and
- <function>hb_buffer_destroy()</function> to dereference.
+ <function>hb_buffer_destroy()</function> to dereference.
</para>
<para>
After construction, each object's properties are accessible only
@@ -71,6 +71,10 @@
Reference manual.
</para>
<para>
+ Note that many object types can be marked as read-only or immutable,
+ facilitating their use in multi-threaded environments.
+ </para>
+ <para>
Key object types provided by HarfBuzz include:
</para>
<itemizedlist spacing="compact">
@@ -110,11 +114,11 @@
</para>
</listitem>
</itemizedlist>
-
+
</section>
-
-
+
+
<section id="object-model-lifecycle">
<title>Object lifecycle management</title>
<para>
@@ -131,7 +135,7 @@
<literal>1</literal>. Client programs can increase the reference
count on an object by calling its
<function>reference()</function> method. Whenever a client
- program is finished with an object, it should call its
+ program is finished with an object, it should call its
corresponding <function>destroy()</function> method. The destroy
method will decrease the reference count on the object and,
whenever the reference count reaches zero, it will also destroy
@@ -141,8 +145,8 @@
All of HarfBuzz's object-lifecycle-management APIs are
thread-safe (unless you compiled HarfBuzz from source with the
<literal>HB_NO_MT</literal> configuration flag), even when the
- object as a whole is not thread-safe.
- It is also permissible to <function>reference()</function> or to
+ object as a whole is not thread-safe.
+ It is also permissible to <function>reference()</function> or to
<function>destroy()</function> the <literal>NULL</literal>
value.
</para>
@@ -160,7 +164,7 @@
as immutable and <function>is_immutable()</function> methods to
test whether or not an object is immutable. Attempts to use
setter functions on immutable objects will fail silently; see the API
- Reference manual for specifics.
+ Reference manual for specifics.
</para>
<para>
Note also that there are no "make mutable" methods. If client
@@ -187,7 +191,7 @@
</para>
</section>
-
+
<section id="object-model-user-data">
<title>User data</title>
<para>
@@ -195,7 +199,7 @@
offer a "user data" mechanism that can be used to attach
arbitrary data to the object. User-data attachment can be
useful for tying the lifecycles of various pieces of data
- together, or for creating language bindings.
+ together, or for creating language bindings.
</para>
<para>
Each object type has a <function>set_user_data()</function>
@@ -220,10 +224,10 @@
existing <literal>user_data</literal>
associated with the specified key.
</para>
- </section>
+ </section>
+
+
-
-
<section id="object-model-blobs">
<title>Blobs</title>
<para>
@@ -238,9 +242,9 @@
you do so in a <literal>hb_blob_t</literal> wrapper.
</para>
<para>
- This allows you to take advantage of HarffBuzz's
+ This allows you to take advantage of HarfBuzz's
reference-counting and <function>destroy</function>
- callbacks. If you allocated the memory for the data using
+ callbacks. If you allocated the memory for the data using
<function>malloc()</function>, you would create the blob using
</para>
<programlisting language="C">
@@ -251,8 +255,12 @@
allocated memory whenever the blob drops its last reference and
is deconstructed. Consequently, the user code can stop worrying
about freeing memory and let the reference-counting machinery
- take care of that.
+ take care of that.
+ </para>
+ <para>
+ Most of the time, blobs are read-only, facilitating their use in
+ immutable objects.
</para>
</section>
-
+
</chapter>
diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml
index e9ea14534..56eba617f 100644
--- a/docs/usermanual-opentype-features.xml
+++ b/docs/usermanual-opentype-features.xml
@@ -65,10 +65,10 @@
</para>
<para>
The algorithms
- used for complex scripts can be quite involved; HarfBuzz tries
+ used for shaping can be quite involved; HarfBuzz tries
to be compatible with the OpenType Layout specification
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
- output of Microsoft's Uniscribe engine. See the <ulink
+ output of Microsoft's Uniscribe engine, to the extent that is feasible and desirable. See the <ulink
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
Typography pages</ulink> for more detail.
</para>
@@ -131,7 +131,7 @@
</para>
<para>
Some OpenType features are defined for the purpose of supporting
- complex-script shaping, and are automatically activated, but
+ script-specific shaping, and are automatically activated, but
only when a buffer's script property is set to a script that the
feature supports.
</para>
diff --git a/docs/usermanual-shaping-concepts.xml b/docs/usermanual-shaping-concepts.xml
index db4e30983..a95b0cbf6 100644
--- a/docs/usermanual-shaping-concepts.xml
+++ b/docs/usermanual-shaping-concepts.xml
@@ -22,7 +22,7 @@
correct amount for each successive glyph.
</para>
<para>
- But, for <emphasis>complex scripts</emphasis>, any combination of
+ But, for other scripts (often unceremoniously called <emphasis>complex scripts</emphasis>), any combination of
several shaping operations may be required, and the rules for how
and when they are applied vary from script to script. HarfBuzz and
other shaping engines implement these rules.
@@ -36,42 +36,35 @@
</para>
</section>
- <section id="complex-scripts">
- <title>Complex scripts</title>
+ <section id="script-specific-shaping">
+ <title>Script-specific shaping</title>
<para>
- In text-shaping terminology, scripts are generally classified as
- either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
- </para>
- <para>
- Complex scripts are those for which transforming the input
- sequence into the final layout requires some combination of
+ In many scripts, transforming the input
+ sequence into the final layout often requires some combination of
operations&mdash;such as context-dependent substitutions,
context-dependent mark positioning, glyph-to-glyph joining,
glyph reordering, or glyph stacking.
</para>
<para>
- In some complex scripts, the shaping rules require that a text
+ In some scripts, the shaping rules require that a text
run be divided into syllables before the operations can be
- applied. Other complex scripts may apply shaping operations over
+ applied. Other scripts may apply shaping operations over
entire words or over the entire text run, with no subdivision
required.
</para>
<para>
- Non-complex scripts, by definition, do not require these
- operations. However, correctly shaping a text run in a
- non-complex script may still involve Unicode normalization,
+ Other scripts, do not require these
+ operations. However, correctly shaping a text run in
+ any script may still involve Unicode normalization,
ligature substitutions, mark positioning, kerning, and applying
- other font features. The key difference is that a text run in a
- non-complex script can be processed sequentially and in the same
- order as the input sequence of Unicode codepoints, without
- requiring an analysis stage.
+ other font features.
</para>
</section>
<section id="shaping-operations">
<title>Shaping operations</title>
<para>
- Shaping a complex-script text run involves transforming the
+ Shaping a text run involves transforming the
input sequence of Unicode codepoints with some combination of
operations that is specified in the shaping model for the
script.
@@ -81,7 +74,7 @@
text run varies from script to script, as do the order that the
operations are performed in and which codepoints are
affected. However, the same general set of shaping operations is
- common to all of the complex-script shaping models.
+ common to all of the script shaping models.
</para>
<itemizedlist>
@@ -92,7 +85,7 @@
some other ("visual") position.
</para>
<para>
- The shaping model for a given complex script might involve
+ The shaping model for a given script might involve
more than one reordering step.
</para>
</listitem>
@@ -119,7 +112,7 @@
particular string pattern.
</para>
<para>
- The shaping model for a given complex script might involve
+ The shaping model for a given script might involve
multiple contextual-substitution operations, each applying
to different target glyphs and patterns, and which are
performed in separate steps.
@@ -138,7 +131,7 @@
Many contextual positioning operations are used to place
<emphasis>mark</emphasis> glyphs (such as diacritics, vowel
signs, and tone markers) with respect to
- <emphasis>base</emphasis> glyphs. However, some complex
+ <emphasis>base</emphasis> glyphs. However, some
scripts may use contextual positioning operations to
correctly place base glyphs as well, such as
when the script uses <emphasis>stacking</emphasis> characters.
@@ -194,7 +187,7 @@
multiple positions).
</para>
<para>
- Some complex scripts require that the text run be split into
+ Some scripts require that the text run be split into
syllables. What constitutes a valid syllable in these
scripts is specified in regular expressions, formed from the
Letter and Mark codepoints, that take the UISC and UIPC
@@ -235,7 +228,7 @@
<listitem>
<para>
The <emphasis>default</emphasis> shaping model handles all
- non-complex scripts, and may also be used as a fallback for
+ scripts with no script-specific shaping model, and may also be used as a fallback for
handling unrecognized scripts.
</para>
</listitem>
@@ -244,7 +237,7 @@
<para>
The <emphasis>Indic</emphasis> shaping model handles the Indic
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
- Malayalam, Oriya, Tamil, Telugu, and Sinhala.
+ Malayalam, Oriya, Tamil, and Telugu.
</para>
<para>
The Indic shaping model was revised significantly in
@@ -310,7 +303,7 @@
<listitem>
<para>
The <emphasis>Universal Shaping Engine</emphasis> (USE)
- shaping model supports complex scripts not covered by one of
+ shaping model supports scripts not covered by one of
the above, script-specific shaping models, including
Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml
index 4534783c2..fdf04b242 100644
--- a/docs/usermanual-what-is-harfbuzz.xml
+++ b/docs/usermanual-what-is-harfbuzz.xml
@@ -237,8 +237,7 @@
<listitem>
<para>
Indic (covering Devanagari, Bengali, Gujarati,
- Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
- Sinhala)
+ Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
</para>
</listitem>
<listitem>
diff --git a/generate_notice.py b/generate_notice.py
new file mode 100644
index 000000000..fab61cbb1
--- /dev/null
+++ b/generate_notice.py
@@ -0,0 +1,732 @@
+#!/usr/bin/env python3
+
+from enum import Enum
+from pathlib import Path
+from typing import Sequence
+from typing import Tuple
+from fontTools import ttLib
+import tempfile
+import subprocess
+import json
+import argparse
+import contextlib
+import os
+import re
+import sys
+
+# list of specific files to be ignored.
+IGNORE_FILE_NAME = [
+ # Exclude myself
+ "generate_notice.py",
+
+ # License files
+ "LICENSE",
+ "LICENSE_APACHE2.TXT",
+ "LICENSE_FSFAP.TXT",
+ "LICENSE_GPLv2.TXT",
+ "LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT",
+ "LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT",
+ "LICENSE_HPND_SELL_VARIANT.TXT",
+ "LICENSE_ISC.TXT",
+ "LICENSE_MIT_MODERN_VARIANT.TXT",
+ "LICENSE_OFL.TXT",
+ "METADATA",
+ "MODULE_LICENSE_MIT",
+ "NOTICE",
+
+ # dictionary which has Copyright word
+ "perf/texts/en-words.txt",
+
+ # broken unreadable font file for fuzzing target
+ "test/fuzzing/fonts/sbix-extents.ttf",
+]
+
+IGNORE_DIR_IF_NO_COPYRIGHT = [
+ "test",
+ "perf",
+]
+
+NO_COPYRIGHT_FILES = [
+ ".ci/build-win32.sh",
+ ".ci/build-win64.sh",
+ ".ci/deploy-docs.sh",
+ ".ci/publish_release_artifact.sh",
+ ".ci/win32-cross-file.txt",
+ ".ci/win64-cross-file.txt",
+ ".circleci/config.yml",
+ ".clang-format",
+ ".codecov.yml",
+ ".editorconfig",
+ ".github/dependabot.yml",
+ ".github/workflows/arm-ci.yml",
+ ".github/workflows/cifuzz.yml",
+ ".github/workflows/configs-build.yml",
+ ".github/workflows/coverity-scan.yml",
+ ".github/workflows/linux-ci.yml",
+ ".github/workflows/macos-ci.yml",
+ ".github/workflows/msvc-ci.yml",
+ ".github/workflows/msys2-ci.yml",
+ "AUTHORS",
+ "BUILD.md",
+ "CMakeLists.txt",
+ "CONFIG.md",
+ "Makefile.am",
+ "NEWS",
+ "OWNERS",
+ "README",
+ "README.android",
+ "README.md",
+ "README.mingw.md",
+ "README.python.md",
+ "README.version",
+ "RELEASING.md",
+ "TESTING.md",
+ "TEST_MAPPING",
+ "THANKS",
+ "autogen.sh",
+ "configure.ac",
+ "docs/HarfBuzz.png",
+ "docs/HarfBuzz.svg",
+ "docs/Makefile.am",
+ "docs/features.dot",
+ "docs/harfbuzz-docs.xml",
+ "docs/harfbuzz-overrides.txt",
+ "docs/harfbuzz-sections.txt",
+ "docs/meson.build",
+ "docs/repacker.md",
+ "docs/serializer.md",
+ "docs/subset-preprocessing.md",
+ "docs/usermanual-buffers-language-script-and-direction.xml",
+ "docs/usermanual-clusters.xml",
+ "docs/usermanual-fonts-and-faces.xml",
+ "docs/usermanual-getting-started.xml",
+ "docs/usermanual-glyph-information.xml",
+ "docs/usermanual-install-harfbuzz.xml",
+ "docs/usermanual-integration.xml",
+ "docs/usermanual-object-model.xml",
+ "docs/usermanual-opentype-features.xml",
+ "docs/usermanual-shaping-concepts.xml",
+ "docs/usermanual-utilities.xml",
+ "docs/usermanual-what-is-harfbuzz.xml",
+ "docs/version.xml.in",
+ "harfbuzz.doap",
+ "meson.build",
+ "meson_options.txt",
+ "mingw-configure.sh",
+ "replace-enum-strings.cmake",
+ "src/ArabicPUASimplified.txt",
+ "src/ArabicPUATraditional.txt",
+ "src/Makefile.am",
+ "src/Makefile.sources",
+ "src/OT/Layout/GPOS/Anchor.hh",
+ "src/OT/Layout/GPOS/AnchorFormat1.hh",
+ "src/OT/Layout/GPOS/AnchorFormat2.hh",
+ "src/OT/Layout/GPOS/AnchorFormat3.hh",
+ "src/OT/Layout/GPOS/AnchorMatrix.hh",
+ "src/OT/Layout/GPOS/ChainContextPos.hh",
+ "src/OT/Layout/GPOS/Common.hh",
+ "src/OT/Layout/GPOS/ContextPos.hh",
+ "src/OT/Layout/GPOS/CursivePos.hh",
+ "src/OT/Layout/GPOS/CursivePosFormat1.hh",
+ "src/OT/Layout/GPOS/ExtensionPos.hh",
+ "src/OT/Layout/GPOS/GPOS.hh",
+ "src/OT/Layout/GPOS/LigatureArray.hh",
+ "src/OT/Layout/GPOS/MarkArray.hh",
+ "src/OT/Layout/GPOS/MarkBasePos.hh",
+ "src/OT/Layout/GPOS/MarkBasePosFormat1.hh",
+ "src/OT/Layout/GPOS/MarkLigPos.hh",
+ "src/OT/Layout/GPOS/MarkLigPosFormat1.hh",
+ "src/OT/Layout/GPOS/MarkMarkPos.hh",
+ "src/OT/Layout/GPOS/MarkMarkPosFormat1.hh",
+ "src/OT/Layout/GPOS/MarkRecord.hh",
+ "src/OT/Layout/GPOS/PairPos.hh",
+ "src/OT/Layout/GPOS/PairPosFormat1.hh",
+ "src/OT/Layout/GPOS/PairPosFormat2.hh",
+ "src/OT/Layout/GPOS/PairSet.hh",
+ "src/OT/Layout/GPOS/PairValueRecord.hh",
+ "src/OT/Layout/GPOS/PosLookup.hh",
+ "src/OT/Layout/GPOS/PosLookupSubTable.hh",
+ "src/OT/Layout/GPOS/SinglePos.hh",
+ "src/OT/Layout/GPOS/SinglePosFormat1.hh",
+ "src/OT/Layout/GPOS/SinglePosFormat2.hh",
+ "src/OT/Layout/GPOS/ValueFormat.hh",
+ "src/OT/Layout/GSUB/AlternateSet.hh",
+ "src/OT/Layout/GSUB/AlternateSubst.hh",
+ "src/OT/Layout/GSUB/AlternateSubstFormat1.hh",
+ "src/OT/Layout/GSUB/ChainContextSubst.hh",
+ "src/OT/Layout/GSUB/Common.hh",
+ "src/OT/Layout/GSUB/ContextSubst.hh",
+ "src/OT/Layout/GSUB/ExtensionSubst.hh",
+ "src/OT/Layout/GSUB/GSUB.hh",
+ "src/OT/Layout/GSUB/Ligature.hh",
+ "src/OT/Layout/GSUB/LigatureSet.hh",
+ "src/OT/Layout/GSUB/LigatureSubst.hh",
+ "src/OT/Layout/GSUB/LigatureSubstFormat1.hh",
+ "src/OT/Layout/GSUB/MultipleSubst.hh",
+ "src/OT/Layout/GSUB/MultipleSubstFormat1.hh",
+ "src/OT/Layout/GSUB/ReverseChainSingleSubst.hh",
+ "src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh",
+ "src/OT/Layout/GSUB/Sequence.hh",
+ "src/OT/Layout/GSUB/SingleSubst.hh",
+ "src/OT/Layout/GSUB/SingleSubstFormat1.hh",
+ "src/OT/Layout/GSUB/SingleSubstFormat2.hh",
+ "src/OT/Layout/GSUB/SubstLookup.hh",
+ "src/OT/Layout/GSUB/SubstLookupSubTable.hh",
+ "src/OT/glyf/CompositeGlyph.hh",
+ "src/OT/glyf/Glyph.hh",
+ "src/OT/glyf/GlyphHeader.hh",
+ "src/OT/glyf/SimpleGlyph.hh",
+ "src/OT/glyf/SubsetGlyph.hh",
+ "src/OT/glyf/VarCompositeGlyph.hh",
+ "src/OT/glyf/composite-iter.hh",
+ "src/OT/glyf/coord-setter.hh",
+ "src/OT/glyf/glyf-helpers.hh",
+ "src/OT/glyf/glyf.hh",
+ "src/OT/glyf/loca.hh",
+ "src/OT/glyf/path-builder.hh",
+ "src/check-c-linkage-decls.py",
+ "src/check-externs.py",
+ "src/check-header-guards.py",
+ "src/check-includes.py",
+ "src/check-libstdc++.py",
+ "src/check-static-inits.py",
+ "src/check-symbols.py",
+ "src/fix_get_types.py",
+ "src/gen-arabic-joining-list.py",
+ "src/gen-arabic-pua.py",
+ "src/gen-arabic-table.py",
+ "src/gen-def.py",
+ "src/gen-emoji-table.py",
+ "src/gen-harfbuzzcc.py",
+ "src/gen-hb-version.py",
+ "src/gen-indic-table.py",
+ "src/gen-os2-unicode-ranges.py",
+ "src/gen-ragel-artifacts.py",
+ "src/gen-tag-table.py",
+ "src/gen-ucd-table.py",
+ "src/gen-use-table.py",
+ "src/gen-vowel-constraints.py",
+ "src/harfbuzz-config.cmake.in",
+ "src/harfbuzz-gobject.pc.in",
+ "src/harfbuzz-icu.pc.in",
+ "src/harfbuzz-subset.cc",
+ "src/harfbuzz-subset.pc.in",
+ "src/harfbuzz.cc",
+ "src/harfbuzz.pc.in",
+ "src/hb-ot-shaper-arabic-joining-list.hh",
+ "src/hb-ot-shaper-arabic-pua.hh",
+ "src/hb-ot-shaper-arabic-table.hh",
+ "src/hb-ot-shaper-indic-table.cc",
+ "src/hb-ot-shaper-use-table.hh",
+ "src/hb-ot-shaper-vowel-constraints.cc",
+ "src/hb-ot-tag-table.hh",
+ "src/hb-ucd-table.hh",
+ "src/hb-unicode-emoji-table.hh",
+ "src/meson.build",
+ "src/ms-use/IndicPositionalCategory-Additional.txt",
+ "src/ms-use/IndicShapingInvalidCluster.txt",
+ "src/ms-use/IndicSyllabicCategory-Additional.txt",
+ "src/sample.py",
+ "src/test-use-table.cc",
+ "src/update-unicode-tables.make",
+ "subprojects/.gitignore",
+ "subprojects/cairo.wrap",
+ "subprojects/freetype2.wrap",
+ "subprojects/glib.wrap",
+ "subprojects/google-benchmark.wrap",
+ "subprojects/packagefiles/ragel/meson.build",
+ "subprojects/ragel.wrap",
+ "subprojects/zlib.wrap",
+ "util/Makefile.am",
+ "util/Makefile.sources",
+ "util/meson.build",
+]
+
+class CommentType(Enum):
+ C_STYLE_BLOCK = 1 # /* ... */
+ C_STYLE_BLOCK_AS_LINE = 2 # /* ... */ but uses multiple lines of block comments.
+ C_STYLE_LINE = 3 # // ...
+ SCRIPT_STYLE_HASH = 4 # # ...
+ OPENTYPE_NAME = 5
+ OPENTYPE_COLLECTION_NAME = 6
+ UNKNOWN = 10000
+
+
+# Helper function of showing error message and immediate exit.
+def fatal(msg: str):
+ sys.stderr.write(str(msg))
+ sys.stderr.write("\n")
+ sys.exit(1)
+
+
+def warn(msg: str):
+ sys.stderr.write(str(msg))
+ sys.stderr.write("\n")
+
+def debug(msg: str):
+ # sys.stderr.write(str(msg))
+ # sys.stderr.write("\n")
+ pass
+
+
+def cleanup_and_join(out_lines: Sequence[str]):
+ while not out_lines[-1].strip():
+ out_lines.pop(-1)
+
+ # If all lines starts from empty space, strip it out.
+ while all([len(x) == 0 or x[0] == ' ' for x in out_lines]):
+ out_lines = [x[1:] for x in out_lines]
+
+ if not out_lines:
+ fatal("Failed to get copyright info")
+ return "\n".join(out_lines)
+
+
+def get_comment_type(copyright_line: str, path_str: str) -> CommentType:
+ # vms_make.com contains multiple copyright header as a string constants.
+ if copyright_line.startswith("#"):
+ return CommentType.SCRIPT_STYLE_HASH
+ if copyright_line.startswith("//"):
+ return CommentType.C_STYLE_LINE
+ return CommentType.C_STYLE_BLOCK
+
+def extract_copyright_font(path_str: str) -> str:
+ path = Path(path_str)
+ if path.suffix in ['.ttf', '.otf', '.dfont']:
+ return extract_from_opentype_name(path, 0)
+ elif path.suffix in ['.ttc', '.otc']:
+ return extract_from_opentype_collection_name(path)
+
+
+# Extract copyright notice and returns next index.
+def extract_copyright_at(lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
+ commentType = get_comment_type(lines[i], path)
+
+ if commentType == CommentType.C_STYLE_BLOCK:
+ return extract_from_c_style_block_at(lines, i, path)
+ elif commentType == CommentType.C_STYLE_LINE:
+ return extract_from_c_style_lines_at(lines, i, path)
+ elif commentType == CommentType.SCRIPT_STYLE_HASH:
+ return extract_from_script_hash_at(lines, i, path)
+ else:
+ fatal("Uknown comment style: %s" % lines[i])
+
+def extract_from_opentype_collection_name(path: str) -> str:
+
+ with open(path, mode="rb") as f:
+ head = f.read(12)
+
+ if head[0:4].decode() != 'ttcf':
+ fatal('Invalid magic number for TTC file: %s' % path)
+ numFonts = int.from_bytes(head[8:12], byteorder="big")
+
+ licenses = set()
+ for i in range(0, numFonts):
+ license = extract_from_opentype_name(path, i)
+ licenses.add(license)
+
+ return '\n\n'.join(licenses)
+
+def extract_from_opentype_name(path: str, index: int) -> str:
+
+ def get_preferred_name(nameID: int, ttf):
+ def get_score(platID: int, encID: int):
+ if platID == 3 and encID == 10:
+ return 0
+ elif platID == 0 and encID == 6:
+ return 1
+ elif platID == 0 and encID == 4:
+ return 2
+ elif platID == 3 and encID == 1:
+ return 3
+ elif platID == 0 and encID == 3:
+ return 4
+ elif platID == 0 and encID == 2:
+ return 5
+ elif platID == 0 and encID == 1:
+ return 6
+ elif platID == 0 and encID == 0:
+ return 7
+ else:
+ return 10000
+
+ best_score = 1000000
+ best_name = None
+
+ if 'name' not in ttf:
+ return None
+
+ for name in ttf['name'].names:
+ if name.nameID != nameID:
+ continue
+
+ score = get_score(name.platformID, name.platEncID)
+ if score < best_score:
+ best_score = score
+ best_name = name
+
+ return best_name
+
+ def get_notice_from_cff(ttf):
+ if 'CFF ' not in ttf:
+ return None
+
+ # Looks like there is no way of getting Notice line in CFF table.
+ # Use the line that has "Copyright" in the string pool.
+ cff = ttf['CFF '].cff
+ for string in cff.strings:
+ if 'Copyright' in string:
+ return string
+ return None
+
+ with contextlib.closing(ttLib.TTFont(path, 0, fontNumber=index)) as ttf:
+ copyright = get_preferred_name(0, ttf)
+ if not copyright:
+ copyright = get_notice_from_cff(ttf)
+ if not copyright:
+ return None
+
+ license_description = get_preferred_name(13, ttf)
+
+ if license_description:
+ copyright = str(copyright) + "\n\n" + str(license_description)
+ else:
+ copyright = str(copyright)
+
+ license_url = get_preferred_name(14, ttf)
+
+ if license_url:
+ copyright = str(copyright) + "\n\n" + str(license_url)
+ else:
+ copyright = str(copyright)
+
+ return copyright
+
+def extract_from_c_style_lines_at(
+ lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
+ def is_copyright_end(line):
+ if line.startswith("//"):
+ return False
+ else:
+ return True
+ start = i
+ while i < len(lines):
+ if is_copyright_end(lines[i]):
+ break
+ i += 1
+ end = i
+
+ if start == end:
+ fatal("Failed to get copyright info")
+
+ out_lines = []
+ for line in lines[start:end]:
+ if line.startswith("//# "): # Andorid.bp uses //# style
+ out_lines.append(line[4:])
+ elif line.startswith("//#"): # Andorid.bp uses //# style
+ out_lines.append(line[3:])
+ elif line.startswith("// "):
+ out_lines.append(line[3:])
+ elif line == "//":
+ out_lines.append(line[2:])
+ else:
+ out_lines.append(line)
+
+ return (cleanup_and_join(out_lines), i + 1)
+
+
+def extract_from_script_hash_at(
+ lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
+ if lines[i].strip()[0] != "#":
+ return (None, i + 1)
+ def is_copyright_end(lines: str, i: int) -> bool:
+ if "#" not in lines[i]:
+ return True
+ # treat double spacing as end of license header
+ if lines[i] == "#" and lines[i+1] == "#":
+ return True
+ return False
+
+ start = i
+ while i < len(lines):
+ if is_copyright_end(lines, i):
+ break
+ i += 1
+ end = i
+
+ if start == end:
+ fatal("Failed to get copyright info")
+
+ out_lines = []
+ for line in lines[start:end]:
+ if line.startswith("# "):
+ out_lines.append(line[2:])
+ elif line == "#":
+ out_lines.append(line[1:])
+ else:
+ out_lines.append(line)
+
+ return (cleanup_and_join(out_lines), i + 1)
+
+
+def extract_from_c_style_block_at(
+ lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
+
+ def is_copyright_end(lines: str, i: int) -> bool:
+ if "*/" in lines[i]:
+ return True
+ if lines[i] == " *" and lines[i + 1] == " *":
+ return True
+ if lines[i] == "" and lines[i + 1] == "":
+ return True
+ return False
+
+ start = i
+ i += 1 # include at least one line
+ while i < len(lines):
+ if is_copyright_end(lines, i):
+ break
+ i += 1
+ end = i + 1
+
+ out_lines = []
+ for line in lines[start:end]:
+ clean_line = line
+
+ # Strip begining "/*" chars
+ if clean_line.startswith("/* "):
+ clean_line = clean_line[3:]
+ if clean_line == "/*":
+ clean_line = clean_line[2:]
+
+ # Strip ending "*/" chars
+ if clean_line.endswith(" */"):
+ clean_line = clean_line[:-3]
+ if clean_line.endswith("*/"):
+ clean_line = clean_line[:-2]
+
+ # Strip starting " *" chars
+ if clean_line.startswith(" * "):
+ clean_line = clean_line[3:]
+ if clean_line == " *":
+ clean_line = clean_line[2:]
+
+ # hb-aots-tester.cpp has underline separater which can be dropped.
+ if path.endswith("test/shape/data/aots/hb-aots-tester.cpp"):
+ clean_line = clean_line.replace("_", "")
+
+ # Strip trailing spaces
+ clean_line = clean_line.rstrip()
+
+ out_lines.append(clean_line)
+
+ return (cleanup_and_join(out_lines), i + 1)
+
+
+# Returns true if the line shows the start of copyright notice.
+def is_copyright_line(line: str, path: str) -> bool:
+ if "Copyright" not in line:
+ return False
+
+ # For avoiding unexpected mismatches, exclude quoted Copyright string.
+ if "`Copyright'" in line:
+ return False
+ if "\"Copyright\"" in line:
+ return False
+
+ if "OpCode_Copyright" in line:
+ return False
+
+ if path.endswith("src/hb-ot-name.h") and "HB_OT_NAME_ID_COPYRIGHT" in line:
+ return False
+
+ return True
+
+def assert_mandatory_copyright(path_str: str):
+ path = Path(path_str)
+ toplevel_dir = str(path).split(os.sep)[0]
+
+ if toplevel_dir in IGNORE_DIR_IF_NO_COPYRIGHT:
+ return
+
+ fatal("%s does not contain Copyright line" % path)
+
+
+# Extract the copyright notice and put it into copyrights arg.
+def do_file(path: str, copyrights: set, no_copyright_files: set):
+ raw = Path(path).read_bytes()
+ basename = os.path.basename(path)
+ dirname = os.path.dirname(path)
+
+ is_font = (dirname.endswith('./test/fuzzing/fonts') or
+ Path(path).suffix in ['.ttf', '.otf', '.dfont', '.ttc', '.otc'])
+
+ if is_font:
+ notice = extract_copyright_font(path)
+ if not notice:
+ assert_mandatory_copyright(path)
+ return
+
+ if not notice in copyrights:
+ copyrights[notice] = []
+ copyrights[notice].append(path)
+ else:
+ try:
+ content = raw.decode("utf-8")
+ except UnicodeDecodeError:
+ content = raw.decode("iso-8859-1")
+
+ if not "Copyright" in content:
+ if path in no_copyright_files:
+ no_copyright_files.remove(path)
+ else:
+ assert_mandatory_copyright(path)
+ return
+
+ lines = content.splitlines()
+
+ # The COPYING in the in-house dir has full OFL license with description.
+ # Use the OFL license description body.
+ if path.endswith("test/shape/data/in-house/COPYING"):
+ notice = cleanup_and_join(lines[9:])
+ copyrights.setdefault(notice, [])
+ copyrights[notice].append(path)
+ return
+
+ # The COPYING in the top dir has MIT-Modern-Variant license with description.
+ # Use the entire file as a license notice.
+ if path.endswith("COPYING") and str(Path(path)) == 'COPYING':
+ notice = cleanup_and_join(lines)
+ copyrights.setdefault(notice, [])
+ copyrights[notice].append(path)
+ return
+
+ i = 0
+ license_found = False
+ while i < len(lines):
+ if is_copyright_line(lines[i], path):
+ (notice, nexti) = extract_copyright_at(lines, i, path)
+ if notice:
+ copyrights.setdefault(notice, [])
+ copyrights[notice].append(path)
+ license_found = True
+
+ i = nexti
+ else:
+ i += 1
+
+ if not license_found:
+ assert_mandatory_copyright(path)
+
+def do_check(path, format):
+ if not path.endswith('/'): # make sure the path ends with slash
+ path = path + '/'
+
+ file_to_ignore = set([os.path.join(path, x) for x in IGNORE_FILE_NAME])
+ no_copyright_files = set([os.path.join(path, x) for x in NO_COPYRIGHT_FILES])
+ copyrights = {}
+
+ for directory, sub_directories, filenames in os.walk(path):
+ # skip .git directory
+ if ".git" in sub_directories:
+ sub_directories.remove(".git")
+
+ for fname in filenames:
+ fpath = os.path.join(directory, fname)
+ if fpath in file_to_ignore:
+ file_to_ignore.remove(fpath)
+ continue
+
+ do_file(fpath, copyrights, no_copyright_files)
+
+ if len(file_to_ignore) != 0:
+ fatal("Following files are listed in IGNORE_FILE_NAME but doesn't exists,.\n"
+ + "\n".join(file_to_ignore))
+
+ if len(no_copyright_files) != 0:
+ fatal("Following files are listed in NO_COPYRIGHT_FILES but doesn't exists.\n"
+ + "\n".join(no_copyright_files))
+
+ if format == Format.notice:
+ print_notice(copyrights, False)
+ elif format == Format.notice_with_filename:
+ print_notice(copyrights, True)
+ elif format == Format.html:
+ print_html(copyrights)
+ elif format == Format.json:
+ print_json(copyrights)
+
+def print_html(copyrights):
+ print('<html>')
+ print("""
+ <head>
+ <style>
+ table {
+ font-family: monospace
+ }
+
+ table tr td {
+ padding: 10px 10px 10px 10px
+ }
+ </style>
+ </head>
+ """)
+ print('<body>')
+ print('<table border="1" style="border-collapse:collapse">')
+ for notice in sorted(copyrights.keys()):
+ files = sorted(copyrights[notice])
+
+ print('<tr>')
+ print('<td>')
+ print('<ul>')
+ for file in files:
+ print('<li>%s</li>' % file)
+ print('</ul>')
+ print('</td>')
+
+ print('<td>')
+ print('<p>%s</p>' % notice.replace('\n', '<br>'))
+ print('</td>')
+
+ print('</tr>')
+
+
+ print('</table>')
+ print('</body></html>')
+
+def print_notice(copyrights, print_file):
+ # print the copyright in sorted order for stable output.
+ for notice in sorted(copyrights.keys()):
+ if print_file:
+ files = sorted(copyrights[notice])
+ print("\n".join(files))
+ print()
+ print(notice)
+ print()
+ print("-" * 67)
+ print()
+
+def print_json(copyrights):
+ print(json.dumps(copyrights))
+
+class Format(Enum):
+ notice = 'notice'
+ notice_with_filename = 'notice_with_filename'
+ html = 'html'
+ json = 'json'
+
+ def __str__(self):
+ return self.value
+
+def main():
+ parser = argparse.ArgumentParser(description="Collect notice headers.")
+ parser.add_argument("--format", dest="format", type=Format, choices=list(Format),
+ default=Format.notice, help="print filename before the license notice")
+ parser.add_argument("--target", dest="target", action='store',
+ required=True, help="target directory to collect notice headers")
+ res = parser.parse_args()
+ do_check(res.target, res.format)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/git.mk b/git.mk
index 6e2708f2d..cd52db1eb 100644
--- a/git.mk
+++ b/git.mk
@@ -204,7 +204,7 @@ git-mk-update:
# Actual .gitignore generation:
###############################################################################
-$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
+$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
@echo "git.mk: Generating $@"
@{ \
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
@@ -375,8 +375,9 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
} | \
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
sed 's@/[.]/@/@g' | \
- LC_ALL=C sort | uniq > $@.tmp && \
- mv $@.tmp $@;
+ LC_ALL=C sort | uniq > .gitignore.tmp && \
+ (mv .gitignore.tmp $@ || (echo "WARNING: Cannot create $@ file; skipping"; \
+ $(RM) .gitignore.tmp));
all: $(srcdir)/.gitignore gitignore-recurse-maybe
gitignore: $(srcdir)/.gitignore gitignore-recurse
diff --git a/harfbuzz.doap b/harfbuzz.doap
index 07699697f..2a5c0e62e 100644
--- a/harfbuzz.doap
+++ b/harfbuzz.doap
@@ -7,11 +7,11 @@
<shortdesc xml:lang="en">Text shaping library</shortdesc>
<homepage
- rdf:resource="http://harfbuzz.org/" />
+ rdf:resource="https://github.com/harfbuzz/harfbuzz" />
<mailing-list
- rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
- <!--download-page
- rdf:resource=""/-->
+ rdf:resource="https://github.com/harfbuzz/harfbuzz/discussions" />
+ <download-page
+ rdf:resource="https://github.com/harfbuzz/harfbuzz/releases" />
<bug-database
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
diff --git a/meson.build b/meson.build
index cd7acff24..cc802f2f5 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
project('harfbuzz', 'c', 'cpp',
- meson_version: '>= 0.52.0',
- version: '3.1.1',
+ meson_version: '>= 0.55.0',
+ version: '6.0.0',
default_options: [
'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway
'cpp_std=c++11',
@@ -21,7 +21,7 @@ pkgmod = import('pkgconfig')
cpp = meson.get_compiler('cpp')
null_dep = dependency('', required: false)
-if cpp.get_id() == 'msvc'
+if cpp.get_argument_syntax() == 'msvc'
# Ignore several spurious warnings for things HarfBuzz does very commonly.
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
@@ -57,10 +57,17 @@ if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') !=
endif
endif
+if host_machine.system() == 'windows'
+ add_project_arguments(cpp.get_supported_arguments([
+ '-Wa,-mbig-obj'
+ ]), language : 'cpp')
+endif
+
check_headers = [
['unistd.h'],
['sys/mman.h'],
['stdbool.h'],
+ ['xlocale.h'],
]
check_funcs = [
@@ -70,56 +77,84 @@ check_funcs = [
['getpagesize'],
['mmap'],
['isatty'],
+ ['uselocale'],
+ ['newlocale'],
]
m_dep = cpp.find_library('m', required: false)
-freetype_dep = null_dep
-if not get_option('freetype').disabled()
- freetype_dep = dependency('freetype2', required: false)
-
- if (not freetype_dep.found() and
- cpp.get_id() == 'msvc' and
- cpp.has_header('ft2build.h'))
- freetype_dep = cpp.find_library('freetype', required: false)
+if meson.version().version_compare('>=0.60.0')
+ # pkg-config: freetype2, cmake: Freetype
+ freetype_dep = dependency('freetype2', 'Freetype',
+ required: get_option('freetype'),
+ default_options: ['harfbuzz=disabled'],
+ allow_fallback: true)
+else
+ # painful hack to handle multiple dependencies but also respect options
+ freetype_opt = get_option('freetype')
+ # we want to handle enabled manually after fallbacks, but also handle disabled normally
+ if freetype_opt.enabled()
+ freetype_opt = false
endif
-
- if not freetype_dep.found()
- # https://github.com/harfbuzz/harfbuzz/pull/2498
- freetype_dep = dependency('freetype2', required: get_option('freetype'),
- fallback: ['freetype2', 'freetype_dep'],
- default_options: ['harfbuzz=disabled'])
+ # try pkg-config name
+ freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt)
+ # when disabled, leave it not-found
+ if not freetype_dep.found() and not get_option('freetype').disabled()
+ # Try cmake name
+ freetype_dep = dependency('Freetype', method: 'cmake', required: false)
+ # Subproject fallback, `allow_fallback: true` means the fallback will be
+ # tried even if the freetype option is set to `auto`.
+ if not freetype_dep.found()
+ freetype_dep = dependency('freetype2',
+ method: 'pkg-config',
+ required: get_option('freetype'),
+ default_options: ['harfbuzz=disabled'],
+ allow_fallback: true)
+ endif
endif
endif
-glib_dep = dependency('glib-2.0', required: get_option('glib'),
- fallback: ['glib', 'libglib_dep'])
-gobject_dep = dependency('gobject-2.0', required: get_option('gobject'),
- fallback: ['glib', 'libgobject_dep'])
+glib_dep = dependency('glib-2.0', required: get_option('glib'))
+gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
graphite_dep = dependency('graphite2', required: get_option('graphite'))
-icu_dep = null_dep
-if not get_option('icu').disabled()
- icu_dep = dependency('icu-uc', required: false)
-
- if (not icu_dep.found() and
- cpp.get_id() == 'msvc' and
- cpp.has_header('unicode/uchar.h') and
- cpp.has_header('unicode/unorm2.h') and
- cpp.has_header('unicode/ustring.h') and
- cpp.has_header('unicode/utf16.h') and
- cpp.has_header('unicode/uversion.h') and
- cpp.has_header('unicode/uscript.h'))
- if get_option('buildtype') == 'debug'
- icu_dep = cpp.find_library('icuucd', required: false)
- else
- icu_dep = cpp.find_library('icuuc', required: false)
+if meson.version().version_compare('>=0.60.0')
+ # pkg-config: icu-uc, cmake: ICU but with components
+ icu_dep = dependency('icu-uc', 'ICU',
+ components: 'uc',
+ required: get_option('icu'),
+ default_options: ['harfbuzz=disabled'],
+ allow_fallback: true)
+else
+ # painful hack to handle multiple dependencies but also respect options
+ icu_opt = get_option('icu')
+ # we want to handle enabled manually after fallbacks, but also handle disabled normally
+ if icu_opt.enabled()
+ icu_opt = false
+ endif
+ # try pkg-config name
+ icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt)
+ # when disabled, leave it not-found
+ if not icu_dep.found() and not get_option('icu').disabled()
+ # Try cmake name
+ icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false)
+ # Try again with subproject fallback. `allow_fallback: true` means the
+ # fallback will be tried even if the icu option is set to `auto`, but
+ # we cannot pass this option until Meson 0.59.0, because no wrap file
+ # is checked into git.
+ if not icu_dep.found()
+ icu_dep = dependency('icu-uc',
+ method: 'pkg-config',
+ required: get_option('icu'))
endif
endif
+endif
- if not icu_dep.found()
- icu_dep = dependency('icu-uc', required: get_option('icu'))
+if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
+ icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '').split()
+ if icu_defs.length() > 0
+ add_project_arguments(icu_defs, language: ['c', 'cpp'])
endif
endif
@@ -130,7 +165,7 @@ if not get_option('cairo').disabled()
cairo_ft_dep = dependency('cairo-ft', required: false)
if (not cairo_dep.found() and
- cpp.get_id() == 'msvc' and
+ cpp.get_argument_syntax() == 'msvc' and
cpp.has_header('cairo.h'))
cairo_dep = cpp.find_library('cairo', required: false)
if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face',
@@ -141,18 +176,13 @@ if not get_option('cairo').disabled()
endif
if not cairo_dep.found()
- # Requires Meson 0.54.0 to use cairo subproject
- if meson.version().version_compare('>=0.54.0')
- # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback
- # dependency cycle here because we have configured freetype2 above with
- # harfbuzz support disabled, so when cairo will lookup freetype2 dependency
- # it will be forced to use that one.
- cairo_dep = dependency('cairo', fallback: 'cairo', required: get_option('cairo'))
- cairo_ft_dep = dependency('cairo-ft', fallback: 'cairo', required: get_option('cairo'))
- elif get_option('cairo').enabled()
- error('cairo feature is enabled but it cannot be found on the system and ' +
- 'meson>=0.54.0 is required to build it as subproject')
- endif
+ # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback
+ # dependency cycle here because we have configured freetype2 above with
+ # harfbuzz support disabled, so when cairo will lookup freetype2 dependency
+ # it will be forced to use that one.
+ cairo_dep = dependency('cairo', required: get_option('cairo'))
+ cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled()
+ cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required)
endif
endif
@@ -179,6 +209,11 @@ endif
if cairo_dep.found()
conf.set('HAVE_CAIRO', 1)
+ if cairo_dep.type_name() == 'internal'
+ conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1)
+ else
+ check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]]
+ endif
endif
if cairo_ft_dep.found()
@@ -211,6 +246,7 @@ if freetype_dep.found()
['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
['FT_Done_MM_Var', {'deps': freetype_dep}],
+ ['FT_Get_Transform', {'deps': freetype_dep}],
]
if freetype_dep.type_name() == 'internal'
@@ -387,19 +423,6 @@ build_summary = {
'Benchmark': get_option('benchmark').enabled(),
},
}
-if meson.version().version_compare('>=0.53')
- foreach section_title, section : build_summary
- summary(section, bool_yn: true, section: section_title)
- endforeach
-else
- summary = ['']
- foreach section_title, section : build_summary
- summary += ' @0@:'.format(section_title)
- foreach feature, value : section
- summary += ' @0@:'.format(feature)
- summary += ' @0@'.format(value)
- endforeach
- summary += ''
- endforeach
- message('\n'.join(summary))
-endif
+foreach section_title, section : build_summary
+ summary(section, bool_yn: true, section: section_title)
+endforeach
diff --git a/mingw-configure.sh b/mingw-configure.sh
index 3281ce382..496cae291 100755
--- a/mingw-configure.sh
+++ b/mingw-configure.sh
@@ -17,12 +17,14 @@ exec "$(dirname "$0")"/configure \
CPP= \
LD= \
CFLAGS="-static-libgcc" \
- CXXFLAGS="-static-libgcc -static-libstdc++" \
+ CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \
CPPFLAGS="-I$HOME/.local/$target/include" \
LDFLAGS=-L$HOME/.local/$target/lib \
PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
--without-icu \
+ --with-gdi \
--with-uniscribe \
+ --with-directwrite=auto \
"$@"
diff --git a/perf/Makefile.am b/perf/Makefile.am
new file mode 100644
index 000000000..1e67b9231
--- /dev/null
+++ b/perf/Makefile.am
@@ -0,0 +1,23 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+SUBDIRS =
+
+EXTRA_DIST += \
+ meson.build \
+ benchmark-font.cc \
+ benchmark-map.cc \
+ benchmark-ot.cc \
+ benchmark-set.cc \
+ benchmark-shape.cc \
+ benchmark-subset.cc \
+ fonts \
+ texts \
+ $(NULL)
+
+# Convenience targets:
+lib:
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
diff --git a/perf/README.md b/perf/README.md
new file mode 100644
index 000000000..91f493514
--- /dev/null
+++ b/perf/README.md
@@ -0,0 +1,54 @@
+# Building and Running
+
+Benchmarks are implemented using [Google Benchmark](https://github.com/google/benchmark).
+
+To build the benchmarks in this directory you need to set the benchmark
+option while configuring the build with meson:
+
+```
+meson build -Dbenchmark=enabled --buildtype=release
+```
+or:
+```
+meson build -Dbenchmark=enabled --buildtype=debugoptimized
+```
+
+
+Then build a specific benchmark binaries with ninja:
+```
+ninja -Cbuild perf/benchmark-set
+```
+or just build the whole project:
+```
+ninja -Cbuild
+```
+
+Finally, to run one of the benchmarks:
+
+```
+./build/perf/benchmark-set
+```
+
+It's possible to filter the benchmarks being run and customize the output
+via flags to the benchmark binary. See the
+[Google Benchmark User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md#user-guide) for more details.
+
+# Profiling
+
+Configure the build to include debug information for profiling:
+
+```
+CXXFLAGS="-fno-omit-frame-pointer" meson --reconfigure build -Dbenchmark=enabled --buildtype=debug
+ninja -Cbuild
+```
+
+Then run the benchmark with perf:
+
+```
+perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
+```
+You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
+
+Finally view the profile with:
+
+perf report
diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc
new file mode 100644
index 000000000..98b6310d2
--- /dev/null
+++ b/perf/benchmark-font.cc
@@ -0,0 +1,245 @@
+#include "benchmark/benchmark.h"
+#include <cassert>
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+ bool is_variable;
+ const char *font_path;
+} default_tests[] =
+{
+ {true , SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
+ {false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"},
+ {true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"},
+ {true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"},
+ {false, SUBSET_FONT_BASE_PATH "Comfortaa-Regular-new.ttf"},
+ {false, SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf"},
+ {false, SUBSET_FONT_BASE_PATH "NotoSerifMyanmar-Regular.otf"},
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+enum operation_t
+{
+ nominal_glyphs,
+ glyph_h_advances,
+ glyph_extents,
+ glyph_shape,
+};
+
+static void
+_hb_move_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
+
+static void
+_hb_line_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
+
+//static void
+//_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {}
+
+static void
+_hb_cubic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, float, float, void *) {}
+
+static void
+_hb_close_path (hb_draw_funcs_t *, void *, hb_draw_state_t *, void *) {}
+
+static hb_draw_funcs_t *
+_draw_funcs_create (void)
+{
+ hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
+ hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
+ hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
+ //hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
+ hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
+ hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
+ return draw_funcs;
+}
+
+static void BM_Font (benchmark::State &state,
+ bool is_var, backend_t backend, operation_t operation,
+ const test_input_t &test_input)
+{
+ hb_font_t *font;
+ unsigned num_glyphs;
+ {
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+ assert (blob);
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ num_glyphs = hb_face_get_glyph_count (face);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ }
+
+ if (is_var)
+ {
+ hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+ hb_font_set_variations (font, &wght, 1);
+ }
+
+ switch (backend)
+ {
+ case HARFBUZZ:
+ hb_ot_font_set_funcs (font);
+ break;
+
+ case FREETYPE:
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+ break;
+ }
+
+ switch (operation)
+ {
+ case nominal_glyphs:
+ {
+ hb_set_t *set = hb_set_create ();
+ hb_face_collect_unicodes (hb_font_get_face (font), set);
+ unsigned pop = hb_set_get_population (set);
+ hb_codepoint_t *unicodes = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
+ hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
+
+ hb_codepoint_t *p = unicodes;
+ for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+ hb_set_next (set, &u);)
+ *p++ = u;
+ assert (p == unicodes + pop);
+
+ for (auto _ : state)
+ hb_font_get_nominal_glyphs (font,
+ pop,
+ unicodes, sizeof (*unicodes),
+ glyphs, sizeof (*glyphs));
+
+ free (glyphs);
+ free (unicodes);
+ hb_set_destroy (set);
+ break;
+ }
+ case glyph_h_advances:
+ {
+ hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
+ hb_position_t *advances = (hb_position_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
+
+ for (unsigned g = 0; g < num_glyphs; g++)
+ glyphs[g] = g;
+
+ for (auto _ : state)
+ hb_font_get_glyph_h_advances (font,
+ num_glyphs,
+ glyphs, sizeof (*glyphs),
+ advances, sizeof (*advances));
+
+ free (advances);
+ free (glyphs);
+ break;
+ }
+ case glyph_extents:
+ {
+ hb_glyph_extents_t extents;
+ for (auto _ : state)
+ for (unsigned gid = 0; gid < num_glyphs; ++gid)
+ hb_font_get_glyph_extents (font, gid, &extents);
+ break;
+ }
+ case glyph_shape:
+ {
+ hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
+ for (auto _ : state)
+ for (unsigned gid = 0; gid < num_glyphs; ++gid)
+ hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr);
+ break;
+ hb_draw_funcs_destroy (draw_funcs);
+ }
+ }
+
+
+ hb_font_destroy (font);
+}
+
+static void test_backend (backend_t backend,
+ const char *backend_name,
+ bool variable,
+ operation_t op,
+ const char *op_name,
+ benchmark::TimeUnit time_unit,
+ const test_input_t &test_input)
+{
+ char name[1024] = "BM_Font/";
+ strcat (name, op_name);
+ strcat (name, "/");
+ const char *p = strrchr (test_input.font_path, '/');
+ strcat (name, p ? p + 1 : test_input.font_path);
+ strcat (name, variable ? "/var" : "");
+ strcat (name, "/");
+ strcat (name, backend_name);
+
+ benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
+ ->Unit(time_unit);
+}
+
+static void test_operation (operation_t op,
+ const char *op_name,
+ benchmark::TimeUnit time_unit)
+{
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ auto& test_input = tests[i];
+ for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+ {
+ bool is_var = (bool) variable;
+
+ test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
+#ifdef HAVE_FREETYPE
+ test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
+#endif
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ benchmark::Initialize(&argc, argv);
+
+ if (argc > 1)
+ {
+ num_tests = argc - 1;
+ tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ tests[i].is_variable = true;
+ tests[i].font_path = argv[i + 1];
+ }
+ }
+
+#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
+
+ TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
+ TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
+ TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
+ TEST_OPERATION (glyph_shape, benchmark::kMicrosecond);
+
+#undef TEST_OPERATION
+
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+
+ if (tests != default_tests)
+ free (tests);
+}
diff --git a/perf/benchmark-map.cc b/perf/benchmark-map.cc
new file mode 100644
index 000000000..f278a0c94
--- /dev/null
+++ b/perf/benchmark-map.cc
@@ -0,0 +1,68 @@
+/*
+ * Benchmarks for hb_map_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include <cassert>
+#include <cstdlib>
+#include "hb.h"
+
+void RandomMap(unsigned size, hb_map_t* out) {
+ hb_map_clear(out);
+
+ srand(size);
+ for (unsigned i = 0; i < size; i++) {
+ while (true) {
+ hb_codepoint_t next = rand();
+ if (hb_map_has (out, next)) continue;
+
+ hb_map_set (out, next, rand ());
+ break;
+ }
+ }
+}
+
+/* Insert a single value into map of varying sizes. */
+static void BM_MapInsert(benchmark::State& state) {
+ unsigned map_size = state.range(0);
+
+ hb_map_t* original = hb_map_create ();
+ RandomMap(map_size, original);
+ assert(hb_map_get_population(original) == map_size);
+
+ auto needle = map_size / 2;
+ auto v = 0;
+ for (auto _ : state) {
+ // TODO(garretrieger): create a copy of the original map.
+ // Needs a hb_map_copy(..) in public api.
+
+ hb_map_set (original, needle++, v++);
+ }
+
+ hb_map_destroy(original);
+}
+BENCHMARK(BM_MapInsert)
+ ->Range(1 << 4, 1 << 20);
+
+/* Single value lookup on map of various sizes. */
+static void BM_MapLookup(benchmark::State& state) {
+ unsigned map_size = state.range(0);
+
+ hb_map_t* original = hb_map_create ();
+ RandomMap(map_size, original);
+ assert(hb_map_get_population(original) == map_size);
+
+ auto needle = map_size / 2;
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(
+ hb_map_get (original, needle++));
+ }
+
+ hb_map_destroy(original);
+}
+BENCHMARK(BM_MapLookup)
+ ->Range(1 << 4, 1 << 20); // Map size
+
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-ot.cc b/perf/benchmark-ot.cc
new file mode 100644
index 000000000..c79c384a0
--- /dev/null
+++ b/perf/benchmark-ot.cc
@@ -0,0 +1,44 @@
+/*
+ * Benchmarks for hb_set_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include "hb-ot.h"
+
+static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
+ hb_script_t script,
+ const char *language_str) {
+
+ hb_language_t language = hb_language_from_string (language_str, -1);
+
+ for (auto _ : state)
+ {
+ hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+ unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+
+ hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+ unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+
+ hb_ot_tags_from_script_and_language (script,
+ language,
+ &script_count /* IN/OUT */,
+ script_tags /* OUT */,
+ &language_count /* IN/OUT */,
+ language_tags /* OUT */);
+ }
+}
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_abcd, HB_SCRIPT_COMMON, "zh_abcd");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_hans, HB_SCRIPT_COMMON, "zh_hans");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abcd, HB_SCRIPT_COMMON, "ab_abcd");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abc, HB_SCRIPT_COMMON, "ab_abc");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcdef_XY, HB_SCRIPT_COMMON, "abcdef_XY");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcd_XY, HB_SCRIPT_COMMON, "abcd_XY");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON cxy_CN, HB_SCRIPT_COMMON, "cxy_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON exy_CN, HB_SCRIPT_COMMON, "exy_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_CN, HB_SCRIPT_COMMON, "zh_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON en_US, HB_SCRIPT_COMMON, "en_US");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN en_US, HB_SCRIPT_LATIN, "en_US");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON none, HB_SCRIPT_LATIN, nullptr);
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN none, HB_SCRIPT_LATIN, nullptr);
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-set.cc b/perf/benchmark-set.cc
new file mode 100644
index 000000000..c170acfc0
--- /dev/null
+++ b/perf/benchmark-set.cc
@@ -0,0 +1,151 @@
+/*
+ * Benchmarks for hb_set_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include <cassert>
+#include <cstdlib>
+#include "hb.h"
+
+void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
+ hb_set_clear(out);
+
+ srand(size * max_value);
+ for (unsigned i = 0; i < size; i++) {
+ while (true) {
+ unsigned next = rand() % max_value;
+ if (hb_set_has (out, next)) continue;
+
+ hb_set_add(out, next);
+ break;
+ }
+ }
+}
+
+// TODO(garretrieger): benchmark union/subtract/intersection etc.
+
+/* Insert a 1000 values into set of varying sizes. */
+static void BM_SetInsert_1000(benchmark::State& state) {
+ unsigned set_size = state.range(0);
+ unsigned max_value = state.range(0) * state.range(1);
+
+ hb_set_t* original = hb_set_create ();
+ RandomSet(set_size, max_value, original);
+ assert(hb_set_get_population(original) == set_size);
+
+ for (auto _ : state) {
+ state.PauseTiming ();
+ hb_set_t* data = hb_set_copy(original);
+ state.ResumeTiming ();
+ for (int i = 0; i < 1000; i++) {
+ hb_set_add(data, i * 2654435761u % max_value);
+ }
+ hb_set_destroy(data);
+ }
+
+ hb_set_destroy(original);
+}
+BENCHMARK(BM_SetInsert_1000)
+ ->Unit(benchmark::kMicrosecond)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+
+/* Insert a 1000 values into set of varying sizes. */
+static void BM_SetOrderedInsert_1000(benchmark::State& state) {
+ unsigned set_size = state.range(0);
+ unsigned max_value = state.range(0) * state.range(1);
+
+ hb_set_t* original = hb_set_create ();
+ RandomSet(set_size, max_value, original);
+ assert(hb_set_get_population(original) == set_size);
+
+ for (auto _ : state) {
+ state.PauseTiming ();
+ hb_set_t* data = hb_set_copy(original);
+ state.ResumeTiming ();
+ for (int i = 0; i < 1000; i++) {
+ hb_set_add(data, i);
+ }
+ hb_set_destroy(data);
+ }
+
+ hb_set_destroy(original);
+}
+BENCHMARK(BM_SetOrderedInsert_1000)
+ ->Unit(benchmark::kMicrosecond)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+
+/* Single value lookup on sets of various sizes. */
+static void BM_SetLookup(benchmark::State& state, unsigned interval) {
+ unsigned set_size = state.range(0);
+ unsigned max_value = state.range(0) * state.range(1);
+
+ hb_set_t* original = hb_set_create ();
+ RandomSet(set_size, max_value, original);
+ assert(hb_set_get_population(original) == set_size);
+
+ auto needle = max_value / 2;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(
+ hb_set_has (original, (needle += interval) % max_value));
+ }
+
+ hb_set_destroy(original);
+}
+BENCHMARK_CAPTURE(BM_SetLookup, ordered, 3)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+BENCHMARK_CAPTURE(BM_SetLookup, random, 12345)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+
+/* Full iteration of sets of varying sizes. */
+static void BM_SetIteration(benchmark::State& state) {
+ unsigned set_size = state.range(0);
+ unsigned max_value = state.range(0) * state.range(1);
+
+ hb_set_t* original = hb_set_create ();
+ RandomSet(set_size, max_value, original);
+ assert(hb_set_get_population(original) == set_size);
+
+ hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ for (auto _ : state) {
+ hb_set_next (original, &cp);
+ }
+
+ hb_set_destroy(original);
+}
+BENCHMARK(BM_SetIteration)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+
+/* Set copy. */
+static void BM_SetCopy(benchmark::State& state) {
+ unsigned set_size = state.range(0);
+ unsigned max_value = state.range(0) * state.range(1);
+
+ hb_set_t* original = hb_set_create ();
+ RandomSet(set_size, max_value, original);
+ assert(hb_set_get_population(original) == set_size);
+
+ for (auto _ : state) {
+ hb_set_t *s = hb_set_create ();
+ hb_set_set (s, original);
+ hb_set_destroy (s);
+ }
+
+ hb_set_destroy(original);
+}
+BENCHMARK(BM_SetCopy)
+ ->Unit(benchmark::kMicrosecond)
+ ->Ranges(
+ {{1 << 10, 1 << 16}, // Set Size
+ {2, 512}}); // Density
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-shape.cc b/perf/benchmark-shape.cc
new file mode 100644
index 000000000..f44b3e58f
--- /dev/null
+++ b/perf/benchmark-shape.cc
@@ -0,0 +1,180 @@
+#include "benchmark/benchmark.h"
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cassert>
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+ const char *font_path;
+ const char *text_path;
+ bool is_variable;
+} default_tests[] =
+{
+
+ {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+ "perf/texts/fa-thelittleprince.txt",
+ false},
+
+ {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+ "perf/texts/fa-words.txt",
+ false},
+
+ {"perf/fonts/Amiri-Regular.ttf",
+ "perf/texts/fa-thelittleprince.txt",
+ false},
+
+ {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
+ "perf/texts/hi-words.txt",
+ false},
+
+ {"perf/fonts/Roboto-Regular.ttf",
+ "perf/texts/en-thelittleprince.txt",
+ false},
+
+ {"perf/fonts/Roboto-Regular.ttf",
+ "perf/texts/en-words.txt",
+ false},
+
+ {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
+ "perf/texts/en-thelittleprince.txt",
+ true},
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+static void BM_Shape (benchmark::State &state,
+ bool is_var,
+ backend_t backend,
+ const test_input_t &input)
+{
+ hb_font_t *font;
+ {
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
+ assert (blob);
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ }
+
+ if (is_var)
+ {
+ hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+ hb_font_set_variations (font, &wght, 1);
+ }
+
+ switch (backend)
+ {
+ case HARFBUZZ:
+ hb_ot_font_set_funcs (font);
+ break;
+
+ case FREETYPE:
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+ break;
+ }
+
+ hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
+ assert (text_blob);
+ unsigned orig_text_length;
+ const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
+
+ hb_buffer_t *buf = hb_buffer_create ();
+ for (auto _ : state)
+ {
+ unsigned text_length = orig_text_length;
+ const char *text = orig_text;
+
+ const char *end;
+ while ((end = (const char *) memchr (text, '\n', text_length)))
+ {
+ hb_buffer_clear_contents (buf);
+ hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
+ hb_buffer_guess_segment_properties (buf);
+ hb_shape (font, buf, nullptr, 0);
+
+ unsigned skip = end - text + 1;
+ text_length -= skip;
+ text += skip;
+ }
+ }
+ hb_buffer_destroy (buf);
+
+ hb_blob_destroy (text_blob);
+ hb_font_destroy (font);
+}
+
+static void test_backend (backend_t backend,
+ const char *backend_name,
+ bool variable,
+ const test_input_t &test_input)
+{
+ char name[1024] = "BM_Shape";
+ const char *p;
+ strcat (name, "/");
+ p = strrchr (test_input.font_path, '/');
+ strcat (name, p ? p + 1 : test_input.font_path);
+ strcat (name, "/");
+ p = strrchr (test_input.text_path, '/');
+ strcat (name, p ? p + 1 : test_input.text_path);
+ strcat (name, variable ? "/var" : "");
+ strcat (name, "/");
+ strcat (name, backend_name);
+
+ benchmark::RegisterBenchmark (name, BM_Shape, variable, backend, test_input)
+ ->Unit(benchmark::kMillisecond);
+}
+
+int main(int argc, char** argv)
+{
+ benchmark::Initialize(&argc, argv);
+
+ if (argc > 2)
+ {
+ num_tests = (argc - 1) / 2;
+ tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ tests[i].is_variable = true;
+ tests[i].font_path = argv[1 + i * 2];
+ tests[i].text_path = argv[2 + i * 2];
+ }
+ }
+
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ auto& test_input = tests[i];
+ for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+ {
+ bool is_var = (bool) variable;
+
+ test_backend (HARFBUZZ, "hb", is_var, test_input);
+#ifdef HAVE_FREETYPE
+ test_backend (FREETYPE, "ft", is_var, test_input);
+#endif
+ }
+ }
+
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+
+ if (tests != default_tests)
+ free (tests);
+}
diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc
new file mode 100644
index 000000000..9b51b794c
--- /dev/null
+++ b/perf/benchmark-subset.cc
@@ -0,0 +1,259 @@
+#include "benchmark/benchmark.h"
+#include <cassert>
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb-subset.h"
+
+
+enum operation_t
+{
+ subset_codepoints,
+ subset_glyphs,
+ instance,
+};
+
+struct axis_location_t
+{
+ hb_tag_t axis_tag;
+ float axis_value;
+};
+
+static const axis_location_t
+_roboto_flex_instance_opts[] =
+{
+ {HB_TAG ('w', 'g', 'h', 't'), 600.f},
+ {HB_TAG ('w', 'd', 't', 'h'), 75.f},
+ {HB_TAG ('o', 'p', 's', 'z'), 90.f},
+ {HB_TAG ('G', 'R', 'A', 'D'), -100.f},
+ {HB_TAG ('s', 'l', 'n', 't'), -3.f},
+ {HB_TAG ('X', 'T', 'R', 'A'), 500.f},
+ {HB_TAG ('X', 'O', 'P', 'Q'), 150.f},
+ {HB_TAG ('Y', 'O', 'P', 'Q'), 100.f},
+ {HB_TAG ('Y', 'T', 'L', 'C'), 480.f},
+ {HB_TAG ('Y', 'T', 'U', 'C'), 600.f},
+ {HB_TAG ('Y', 'T', 'A', 'S'), 800.f},
+ {HB_TAG ('Y', 'T', 'D', 'E'), -50.f},
+ {HB_TAG ('Y', 'T', 'F', 'I'), 600.f},
+};
+
+static const axis_location_t
+_mplus_instance_opts[] =
+{
+ {HB_TAG ('w', 'g', 'h', 't'), 800.f},
+};
+
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+ const char *font_path;
+ unsigned max_subset_size;
+ const axis_location_t *instance_opts;
+ unsigned num_instance_opts;
+} default_tests[] =
+{
+ {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0},
+ {SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)},
+ {SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)},
+#if 0
+ {"perf/fonts/NotoSansCJKsc-VF.ttf", 100000},
+#endif
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+
+void AddCodepoints(const hb_set_t* codepoints_in_font,
+ unsigned subset_size,
+ hb_subset_input_t* input)
+{
+ auto *unicodes = hb_subset_input_unicode_set (input);
+ hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ for (unsigned i = 0; i < subset_size; i++) {
+ // TODO(garretrieger): pick randomly.
+ if (!hb_set_next (codepoints_in_font, &cp)) return;
+ hb_set_add (unicodes, cp);
+ }
+}
+
+void AddGlyphs(unsigned num_glyphs_in_font,
+ unsigned subset_size,
+ hb_subset_input_t* input)
+{
+ auto *glyphs = hb_subset_input_glyph_set (input);
+ for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
+ // TODO(garretrieger): pick randomly.
+ hb_set_add (glyphs, i);
+ }
+}
+
+// Preprocess face and populate the subset accelerator on it to speed up
+// the subsetting operations.
+static hb_face_t* preprocess_face(hb_face_t* face)
+{
+ hb_face_t* new_face = hb_subset_preprocess(face);
+ hb_face_destroy(face);
+ return new_face;
+}
+
+/* benchmark for subsetting a font */
+static void BM_subset (benchmark::State &state,
+ operation_t operation,
+ const test_input_t &test_input,
+ bool hinting)
+{
+ unsigned subset_size = state.range(0);
+
+ hb_face_t *face = nullptr;
+
+ static hb_face_t *cached_face;
+ static const char *cached_font_path;
+
+ if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
+ {
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+ assert (blob);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+
+ face = preprocess_face (face);
+
+ if (cached_face)
+ hb_face_destroy (cached_face);
+
+ cached_face = hb_face_reference (face);
+ cached_font_path = test_input.font_path;
+ }
+ else
+ face = hb_face_reference (cached_face);
+
+ hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+ assert (input);
+
+ if (!hinting)
+ hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
+
+ switch (operation)
+ {
+ case subset_codepoints:
+ {
+ hb_set_t* all_codepoints = hb_set_create ();
+ hb_face_collect_unicodes (face, all_codepoints);
+ AddCodepoints(all_codepoints, subset_size, input);
+ hb_set_destroy (all_codepoints);
+ }
+ break;
+
+ case subset_glyphs:
+ {
+ unsigned num_glyphs = hb_face_get_glyph_count (face);
+ AddGlyphs(num_glyphs, subset_size, input);
+ }
+ break;
+
+ case instance:
+ {
+ hb_set_t* all_codepoints = hb_set_create ();
+ hb_face_collect_unicodes (face, all_codepoints);
+ AddCodepoints(all_codepoints, subset_size, input);
+ hb_set_destroy (all_codepoints);
+
+ for (unsigned i = 0; i < test_input.num_instance_opts; i++)
+ hb_subset_input_pin_axis_location (input, face,
+ test_input.instance_opts[i].axis_tag,
+ test_input.instance_opts[i].axis_value);
+ }
+ break;
+ }
+
+ for (auto _ : state)
+ {
+ hb_face_t* subset = hb_subset_or_fail (face, input);
+ assert (subset);
+ hb_face_destroy (subset);
+ }
+
+ hb_subset_input_destroy (input);
+ hb_face_destroy (face);
+}
+
+static void test_subset (operation_t op,
+ const char *op_name,
+ bool hinting,
+ benchmark::TimeUnit time_unit,
+ const test_input_t &test_input)
+{
+ if (op == instance && test_input.instance_opts == nullptr)
+ return;
+
+ char name[1024] = "BM_subset/";
+ strcat (name, op_name);
+ strcat (name, "/");
+ const char *p = strrchr (test_input.font_path, '/');
+ strcat (name, p ? p + 1 : test_input.font_path);
+ if (!hinting)
+ strcat (name, "/nohinting");
+
+ benchmark::RegisterBenchmark (name, BM_subset, op, test_input, hinting)
+ ->Range(10, test_input.max_subset_size)
+ ->Unit(time_unit);
+}
+
+static void test_operation (operation_t op,
+ const char *op_name,
+ const test_input_t *tests,
+ unsigned num_tests,
+ benchmark::TimeUnit time_unit)
+{
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ auto& test_input = tests[i];
+ test_subset (op, op_name, true, time_unit, test_input);
+ test_subset (op, op_name, false, time_unit, test_input);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ benchmark::Initialize(&argc, argv);
+
+ if (argc > 1)
+ {
+ num_tests = (argc - 1) / 2;
+ tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ tests[i].font_path = argv[1 + i * 2];
+ tests[i].max_subset_size = atoi (argv[2 + i * 2]);
+ }
+ }
+
+#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit)
+
+ TEST_OPERATION (subset_glyphs, benchmark::kMillisecond);
+ TEST_OPERATION (subset_codepoints, benchmark::kMillisecond);
+ TEST_OPERATION (instance, benchmark::kMillisecond);
+
+#undef TEST_OPERATION
+
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+
+ if (tests != default_tests)
+ free (tests);
+}
diff --git a/perf/meson.build b/perf/meson.build
index c3b0e3e4a..ae122f439 100644
--- a/perf/meson.build
+++ b/perf/meson.build
@@ -1,27 +1,62 @@
google_benchmark = subproject('google-benchmark')
google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
-ttf_parser_dep = null_dep
-if get_option('experimental_api') and add_languages('rust', required: false, native: true)
- ttf_parser_dep = subproject('ttf-parser').get_variable('ttf_parser_dep')
-endif
+benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
+ dependencies: [
+ google_benchmark_dep, freetype_dep,
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz],
+ install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
-if ttf_parser_dep.found()
- benchmark_cpp_args = ['-DHAVE_TTFPARSER']
-else
- benchmark_cpp_args = []
-endif
+benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
+ dependencies: [
+ google_benchmark_dep,
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz],
+ install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
-benchmark('perf', executable('perf', 'perf.cc',
+benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
dependencies: [
- google_benchmark_dep, freetype_dep,
+ google_benchmark_dep,
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz],
+ install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
+ dependencies: [
+ google_benchmark_dep,
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz],
+ install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
- # the last two, thread and dl, aren't nice as ttf-parser isn't no_std yet
- # https://github.com/RazrFalcon/ttf-parser/issues/29
- ttf_parser_dep, thread_dep, cpp.find_library('dl'),
+benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
+ dependencies: [
+ google_benchmark_dep, freetype_dep,
],
- cpp_args: benchmark_cpp_args,
+ cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
-), workdir: join_paths(meson.current_source_dir(), '..'), timeout: 100)
+), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
+ dependencies: [
+ google_benchmark_dep,
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz, libharfbuzz_subset],
+ install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
diff --git a/perf/perf-draw.hh b/perf/perf-draw.hh
deleted file mode 100644
index 12581bc0d..000000000
--- a/perf/perf-draw.hh
+++ /dev/null
@@ -1,177 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-#include "hb-ot.h"
-#include "hb-ft.h"
-#include FT_OUTLINE_H
-
-#ifdef HAVE_TTFPARSER
-#include "ttfparser.h"
-#endif
-
-#define HB_UNUSED __attribute__((unused))
-
-static void
-_hb_move_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_hb_line_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_hb_quadratic_to (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
- hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
- void *user_data HB_UNUSED) {}
-
-static void
-_hb_cubic_to (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
- hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
- hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
- void *user_data HB_UNUSED) {}
-
-static void
-_hb_close_path (void *user_data HB_UNUSED) {}
-
-static void
-_ft_move_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-static void
-_ft_line_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-static void
-_ft_conic_to (const FT_Vector* control HB_UNUSED, const FT_Vector* to HB_UNUSED,
- void* user HB_UNUSED) {}
-
-static void
-_ft_cubic_to (const FT_Vector* control1 HB_UNUSED, const FT_Vector* control2 HB_UNUSED,
- const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-#ifdef HAVE_TTFPARSER
-static void _tp_move_to (float x HB_UNUSED, float y HB_UNUSED, void *data HB_UNUSED) {}
-static void _tp_line_to (float x, float y, void *data) {}
-static void _tp_quad_to (float x1, float y1, float x, float y, void *data) {}
-static void _tp_curve_to (float x1, float y1, float x2, float y2, float x, float y, void *data) {}
-static void _tp_close_path (void *data) {}
-#endif
-
-static void draw (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
-{
- hb_font_t *font;
- unsigned num_glyphs;
- {
- hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
- assert (blob);
- hb_face_t *face = hb_face_create (blob, 0);
- hb_blob_destroy (blob);
- num_glyphs = hb_face_get_glyph_count (face);
- font = hb_font_create (face);
- hb_face_destroy (face);
- }
-
- if (backend == HARFBUZZ)
- {
- if (is_var)
- {
- hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
- hb_font_set_variations (font, &wght, 1);
- }
- hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to);
- hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to);
- hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to);
- hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to);
- hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path);
-
- for (auto _ : state)
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
-
- hb_draw_funcs_destroy (draw_funcs);
- }
- else if (backend == FREETYPE)
- {
- if (is_var)
- {
- hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
- hb_font_set_variations (font, &wght, 1);
- }
- hb_ft_font_set_funcs (font);
- FT_Face ft_face = hb_ft_font_get_face (font);
- hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
-
- FT_Outline_Funcs draw_funcs;
- draw_funcs.move_to = (FT_Outline_MoveToFunc) _ft_move_to;
- draw_funcs.line_to = (FT_Outline_LineToFunc) _ft_line_to;
- draw_funcs.conic_to = (FT_Outline_ConicToFunc) _ft_conic_to;
- draw_funcs.cubic_to = (FT_Outline_CubicToFunc) _ft_cubic_to;
- draw_funcs.shift = 0;
- draw_funcs.delta = 0;
-
- for (auto _ : state)
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- {
- FT_Load_Glyph (ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
- FT_Outline_Decompose (&ft_face->glyph->outline, &draw_funcs, nullptr);
- }
- }
- else if (backend == TTF_PARSER)
- {
-#ifdef HAVE_TTFPARSER
- ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
- hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
- assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
- if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
-
- ttfp_outline_builder builder;
- builder.move_to = _tp_move_to;
- builder.line_to = _tp_line_to;
- builder.quad_to = _tp_quad_to;
- builder.curve_to = _tp_curve_to;
- builder.close_path = _tp_close_path;
-
- ttfp_rect bbox;
- for (auto _ : state)
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- ttfp_outline_glyph (tp_font, builder, &builder, gid, &bbox);
-
- hb_blob_destroy (blob);
- free (tp_font);
-#endif
- }
- else abort ();
-
- hb_font_destroy (font);
-}
-
-#define FONT_BASE_PATH "test/subset/data/fonts/"
-
-BENCHMARK_CAPTURE (draw, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
diff --git a/perf/perf-extents.hh b/perf/perf-extents.hh
deleted file mode 100644
index c7bc84c92..000000000
--- a/perf/perf-extents.hh
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-#include "hb-ft.h"
-#include "hb-ot.h"
-
-#ifdef HAVE_TTFPARSER
-#include "ttfparser.h"
-#endif
-
-static void extents (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
-{
- hb_font_t *font;
- unsigned num_glyphs;
- {
- hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
- assert (blob);
- hb_face_t *face = hb_face_create (blob, 0);
- hb_blob_destroy (blob);
- num_glyphs = hb_face_get_glyph_count (face);
- font = hb_font_create (face);
- hb_face_destroy (face);
- }
-
- if (is_var)
- {
- hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
- hb_font_set_variations (font, &wght, 1);
- }
-
- if (backend == HARFBUZZ || backend == FREETYPE)
- {
- if (backend == FREETYPE)
- {
- hb_ft_font_set_funcs (font);
- hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
- }
-
- hb_glyph_extents_t extents;
- for (auto _ : state)
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- hb_font_get_glyph_extents (font, gid, &extents);
- }
- else if (backend == TTF_PARSER)
- {
-#ifdef HAVE_TTFPARSER
- ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
- hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
- assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
- if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
-
- ttfp_rect bbox;
- for (auto _ : state)
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- ttfp_get_glyph_bbox(tp_font, gid, &bbox);
-
- hb_blob_destroy (blob);
- free (tp_font);
-#endif
- }
-
- hb_font_destroy (font);
-}
-
-#define FONT_BASE_PATH "test/subset/data/fonts/"
-
-BENCHMARK_CAPTURE (extents, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
-
diff --git a/perf/perf-shaping.hh b/perf/perf-shaping.hh
deleted file mode 100644
index 85ee19b77..000000000
--- a/perf/perf-shaping.hh
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-
-static void shape (benchmark::State &state, const char *text_path,
- hb_direction_t direction, hb_script_t script,
- const char *font_path)
-{
- hb_font_t *font;
- {
- hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
- assert (blob);
- hb_face_t *face = hb_face_create (blob, 0);
- hb_blob_destroy (blob);
- font = hb_font_create (face);
- hb_face_destroy (face);
- }
-
- hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (text_path);
- assert (text_blob);
- unsigned text_length;
- const char *text = hb_blob_get_data (text_blob, &text_length);
-
- hb_buffer_t *buf = hb_buffer_create ();
- for (auto _ : state)
- {
- hb_buffer_add_utf8 (buf, text, text_length, 0, -1);
- hb_buffer_set_direction (buf, direction);
- hb_buffer_set_script (buf, script);
- hb_shape (font, buf, nullptr, 0);
- hb_buffer_clear_contents (buf);
- }
- hb_buffer_destroy (buf);
-
- hb_blob_destroy (text_blob);
- hb_font_destroy (font);
-}
-
-BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - Amiri,
- "perf/texts/fa-thelittleprince.txt",
- HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
- "perf/fonts/Amiri-Regular.ttf");
-BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - NotoNastaliqUrdu,
- "perf/texts/fa-thelittleprince.txt",
- HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
- "perf/fonts/NotoNastaliqUrdu-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, fa-monologue.txt - Amiri,
- "perf/texts/fa-monologue.txt",
- HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
- "perf/fonts/Amiri-Regular.ttf");
-BENCHMARK_CAPTURE (shape, fa-monologue.txt - NotoNastaliqUrdu,
- "perf/texts/fa-monologue.txt",
- HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
- "perf/fonts/NotoNastaliqUrdu-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, en-thelittleprince.txt - Roboto,
- "perf/texts/en-thelittleprince.txt",
- HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
- "perf/fonts/Roboto-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, en-words.txt - Roboto,
- "perf/texts/en-words.txt",
- HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
- "perf/fonts/Roboto-Regular.ttf");
diff --git a/perf/perf.cc b/perf/perf.cc
deleted file mode 100644
index a364b910b..000000000
--- a/perf/perf.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "perf-shaping.hh"
-#ifdef HAVE_FREETYPE
-enum backend_t { HARFBUZZ, FREETYPE, TTF_PARSER };
-#include "perf-extents.hh"
-#ifdef HB_EXPERIMENTAL_API
-#include "perf-draw.hh"
-#endif
-#endif
-
-BENCHMARK_MAIN ();
diff --git a/perf/run.sh b/perf/run.sh
deleted file mode 100755
index c7dc6e0c2..000000000
--- a/perf/run.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-CXX=clang++
-FONT=fonts/NotoNastaliqUrdu-Regular.ttf
-TEXT=texts/fa-monologue.txt
-
-$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
- -lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
- -I../src $FLAGS $SOURCES \
- -DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
- -DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
- -o hb-shape -g -O2 # -O3 \
- #-march=native -mtune=native \
- #-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
- #-Rpass-analysis=loop-vectorize -fsave-optimization-record
-
-# -march=native: enable all vector instructions current CPU can offer
-# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
-
-#sudo rm capture.syscap > /dev/null
-#sysprof-cli -c "./a.out $@"
-#sysprof capture.syscap
-
-perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
-#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
-#perf report -g
diff --git a/perf/texts/fa-monologue.txt b/perf/texts/fa-monologue.txt
deleted file mode 100644
index c41257c14..000000000
--- a/perf/texts/fa-monologue.txt
+++ /dev/null
@@ -1 +0,0 @@
-من اسمم کاظمه. ما توی یه کوچه بن بست خونه داریم. کوچه‌مون خاکیه. اونوقت خیلی پایئن تر از خونه ما - زیاد پایین نه - اینور می‌پیچی یه نونواس. از اونجا صاف می‌ریم اینجا. یه خیابونه اینجا. اونوقت خیلی پایین‌ترش یه حمومه. بعداً یه بقالی هم دم خونمونه. یه خرده انور خرابه، یه قصابیه. قصابه با بابام رفیقه. پشت خونمون یه دباغیه. اینقده بچه گوسفند توشه! خونه‌مون ساس داره. ساس کوچیک و سیاس. هر جا بزنه جاش باد می‌کنه. وقتی داره از دیوار اتاق می‌ره بالا، نمی‌تونه خودشو نگه داره، می‌افته رو تن ما، می‌گیره خونمونو می‌مکه. یه دفعه همه اثاث مثاثامونو ریختیم بیرون، یه عالمه دوا خریدیم زدیم همه جا: به رختخوابا،‌ زیر زیلو، سوراخ سنبه‌ها. ولی ساسها بیشتر شدن، کمتر نشدن. بابام توی حموم کار می‌کنه. دوتا برادر داریم، یه خواهر: من و مصطفی و زهرا کوچولو. بابا وقتی داره شب می‌شه برمی‌گرده خونه. همیشه استخوناش درد می‌کنه. سر هیچی به هیچی می‌گیره می‌زنه‌مون، بازهم طلبکاره. مثلاً وسط سال، صبح ساعت شیش می‌آد می‌گه، «پاشو برو سیگار بفروش، پول دربیار لباس بخر!» من هم می‌گم: «لباس می‌خوام چی‌ کار؟» اون هم می‌گیره با کمربند حالمونو جا می‌آره. باز خوبه سه ماه تعطیلی خودمون می‌ریم کار می‌کنیم. یه کارخونه هست. می‌ریم اونجا قابلمه درست می‌کنیم، کاسه درست می‌کنیم، عصر که شونصد تا کاسه درست کردیم، دستگارو تمیز می‌کنیم برمی‌گردیم خونه. پارسال هفته‌ای پنجاه تومن مزد می‌دادن. امسال دیگه خدا می‌دونه. با همه این حرفا، بمیریم بهتره آقا! هر روز هر روز کتک. بابام دیشب بیخودی مصطفی رو گرفت زد. گرفت زدش گفت: «چرا وقتی می‌ری دست به آب، سر پا می‌شاشی؟ بشی بشاش!» مصطفی‌مون هیچی حالیش نمی‌شه. قد زهرامون بوده که از بالا پشت بوم افتاده، رگ کله‌اش تکون خرده. حالا سیزده سالشه. نه چارده،‌ چارده سالشه. داداش بزرگ‌ مونه. الان مدرسه عقب افتاده‌ها درس می‌خونه. آب، بابا، بار میخونه یاد بگیره، بیاد جلو. دو سه کلمه بلده حرف بزنه ولی چیزه... نمیتونه قشنگ حرف بزنه. بابام می‌خواد از مدرسه ورش داره، بذاره یه جا که کار یاد بگیره. بابا زهرا را از همه بیشتر می‌خواد. اون هم هر کاری دلش بخواد می‌کنه. هرچی می‌گیم گوش نمی‌کنه، می‌ره تو جوب محل کثافت‌کاری می‌کنه. اون روزی حواسم نبود، رفت یه مشت دیگ مونده سر کوچه بود ورداشت خورد. شب دلش درد گرفت نزدیک بود بمیره. اونوقت بابام اومد گرفت منو با شیلنگ کشت. آقا مگه شهر هرته؟ خر کتک می‌خوره. دیگه چرا ما رو می‌زنن؟ برن به خر بزنن! آخه من که نمی‌تونم همه‌ش مواظب زهرا باشم. راستی یه صاحب حیاط داریم، خیلی بد اخلاقه آقا! اسمش عباس آقاس. صبح می‌ره ظهر می‌آد. سپور شهرداریه. بیست و چار ساعت می‌آد بند میکنه به ما، میگه: «آب زیاد مصرف نکنین، چاه پر میشه.» زهرامون که گاهی گریه می‌کنه، دادش بلند می‌شه می‌گه: «صدای این تخم‌سگو خفه کنین!» اونوقت که مادرمون زنده بود، یه دفعه می‌خواست از دست عباس آقا نفت بریزه سرش، خودشو آتیش بزنه. عباس آقا اصلاً رحم حالیش نمی‌شه؛ پسر سیزده ساله‌شو گرفته از خونه انداخته بیرون. اون هم رفته توی کوچه‌ پس ‌کوچه‌‌ها ول شده. حالا خدا می‌دونه کجاس، چه کار می‌کنه،‌ از کجا می‌آره می‌خوره. بچه‌ها می‌گن: «شب‌ها می‌ره توی پارک‌ها پیش سگها می‌خوابه.» که رفته دهات خونهٔ باباش، می‌گه دیگه نمی‌آم تهران. آقا، ما هم دلمون می‌خواد میرفتیم دهمون با گوسفندها بازی می‌کردیم؛ با بابا بزرگ‌مون می‌رفتیم دشت بز می‌چروندیم،‌ بادوم پاک می‌کردیم، انگور می‌چیدیم. دهمون ولی خیلی دوره آخه! زن عباس آقا حق داره، آقا! محله‌مون خیلی بده. هر روز اونجا دعواس، دعوا، چاقو کشی. توی خرابه هم پر معتاده، بگی دوهزار تا هم بیشتر. می‌رن اونجا قمار می‌کنن، شیره می‌کشن، آمپول می‌زنن تو رگشون. ماهم از ترس معتادها جرأت نمی‌کنیم از خونه بریم کوچه، یه ذره بازی کنیم. از کمیته‌م نمی‌ترسن، میگیرن بچه‌های مردمو می‌دزدن، میبرن توی کوره‌ها،‌ توی دلاشون چیز قایم می‌کنن؛ هروئین قایم میکنن. یه امیر ریزه هست تریاکیه، اون روزی اومد خرم کنه، گفت: «بیا سوار ماشین بشیم، بریم یه جائی.» من هم از ترسم خر نشدم. یه چیز خنده دار بگم بخندی، آقا: اینورمون یه همسایه داریم، اسمش ربابه. انوقت توپ،‌ لنگه کفش، تنکه، هرچی بیفته خونشون،‌ شوهرش ور می‌داره می‌اندازه توی آب انبارشون. هروقت هم کوچه شلوغ بشه، شوهر رباب می‌آد بیرون می‌گه: «واق، عو!» اون هم مث مصطفی‌ ما لقوه‌ایه‌؛ دستش می‌لزره، همه جاش می‌لرزه. اون روز اومد دم دکون، رفت اونور جوب نشت. این یکی همسایه‌مون رفت یه کتاب دربارهٔ خدا و فرشته‌ها آورد براش خوند. رباب خانم خودش خونه یه اعیونه کار می‌کنه؛ چیزاشونو می‌شوره، باغ‌شونو آب می‌ده؛ کلفتی می‌کنه. بعد همه‌ش می‌آد پز اربابشو می‌ده. الان دیگه همه اهل محل می‌دونن باغ خونهٔ ارباب رباب خانوم اندازه پارک شهره. استخرش از مال پارک شهر هم گنده‌تره. هروقت هم که ارباب می‌خواد‌ آبتنی کنه،‌ اول یه قطره دوای مخصوص هست، می‌ریزه توی استخر که آب‌شو می‌کنه مث اشک چشم. بعد می‌ره زیر دوش، با عطر و گلاب خودشو می‌شوره. بعد می‌پره توی استخر، می‌گیره شوخی شوخی آب می‌پاشه به رباب خانوم. زن اربابش هم خارجیه. مال همون کشوریه که شیش ماه شبه، شیش ماه روز. رباب یه چاخان‌هایی می‌کنه که کلهٔ آدم سوت می‌کشه! می‌گه ارباب یه سگ پشمالو داره،‌ اسمش مونیکاس. قسم می‌خوره می‌گه مونیکا غذاشو با کارد و چنگال می‌خوره. اللَه اکبر به این دروغ. یه پیرزنه هم هست سر کوچمونه. با خودش تنهایی زندگی می‌کنه. اسمش ننه غلامه. هشتاد نود سالشه ولی خجالت نمی‌کشه،‌ از امریکا خوشش می‌آد. همه ازش می‌ترسن؛ هر وفت بیاد بیرون، فحش می‌ده، جیغ و ویغ می‌زنه. مثلا من اذیتش کردم، می‌آد سر فحش‌رو می‌کشه به تو. وقتی بچه‌ها بخوان لج‌شو در‌بیارن، می‌گن: «مرگ بر امریکا!» اونوقت اون هم حرصش می‌گیره، هزار تا فحش بی‌ناموسی و خوار و مادر می‌کشه به جون همه. ننه غلام دیونه‌س. بعضی وقتا هم با‌ آدم خوبه. یه روز من و زهرا رو گرفت به زور برد خونه‌ش، کله پاچه داد، گفت «بخورین!» ما هم خوردیم. ته کاسه یه لقمه موند که روش یه عالمه مو بود. گفت: «اگه نخورین با همین چاقو سرتونو می‌برم.» ما هم از ترس جونمون خوردیم. ننه غلام وقتی سر حاله، چیز می‌آره می‌ده آدم. مثلا یکی زخمه،‌ دوا می‌آره بهش می‌ده. مثلا کسی چیزی نداره، چیز می‌آره بهش می‌ده، وسط کوچه‌مون یه خونه‌س که دخترهاش خرابن، آقا. اونوقت شیره‌ای‌ها و چاقوکش‌ها می‌رن خونه‌شون، کار بد می‌کنن. بعضی وقتا هم دختر‌هاش لباس سرخ و زرد تن می‌کنن و کفش پاشنه بلند تق‌تقی می‌پوشن، می‌رن واسه بالاشهری‌ها قر می‌دن. یه دفعه هم داشتم می‌رفتم پیش بچه‌ها «لیس پس لیس» بازی کنم که دختر کوچیکه‌ش امیر ریزه رو صدا کرد و بهش گفت: «تو چقدر پاهات لاغره!» بعد امیر ریزه هم نامردی نکرد. گفت:«خودت چرا لمبه‌هات چاقه؟» بعد دوتایی کرکر خندیدن. خودم با همین دو تا چشمام دیدم، آقا! اونوقت ما هم که می‌بینیم محله‌مون پر از بی‌تربیتی‌یه، زدیم با هفت‌تا از بچه محلامون قهر کردیم. با اون هفت‌تا هم بمیرم آشتی نمی‌کنم، آقا. با یکی‌شون یه ساله قهریم، اسمش محمده. یه روز سر کوچه‌مون عروسی بود، ما هم داشتیم بازی می‌کردیم. من دراومدم به محمد گفتم: «محمد امشب چه خبره؟ آبجی‌ت می‌ره حجله؟» ناراحت شد، گفت: «باهات قهرم.» من هم گفتم: «چه بهتر! می‌رم درسامو می‌خونم.» به خدا ما چه می‌دونستیم، به خیالمون عروسی آبجیشه، آقا! فقط با دو نفر دوستیم: مهدی ملخ و حسن گامبو. مهدی از بس مردنیه، همه ملخ صداش می‌کنن. باباش قوری بست می‌زنه. وسط بازی یهو پیداش می‌شه، می‌آد می‌گه: «اگه منو بازی ندین، بازی‌تونو بهم می‌زنم.» اونوقت تا که دس بهش می‌خوره، جیغش می‌ره هوا، میگه: «گه خوردم، گه خوردم.» اونوقت می‌ره از حرصش با میخ یه شکل‌هایی می‌کشه روی دیوار، می‌گه: «این عکس کاظمه.» فسقلی فوتش کنی، قل می‌خوره، ها. آقا، ما دوچرخه خیلی دوست داریم، بعضی وقتا می‌ریم یه تومن می‌دیم چرخ کرایه می‌کنیم. حسن گامبو زورش می‌آد، با سنگ می‌زنه، می‌گه: «منو باید سوار کنی.» من هم می‌بینم داره دلش می‌شکنه، می‌گم: «بیا تو هم سوار شو!» داداش حسن گامبو پنج ماهه رفته لب مرز با خارجیا بجنگه. حسن می‌گه: «رفته امریکا رو نابود کنه، برگرده.» بابای حسن آهنکاره؛ یعنی قالب می‌سازه، پشقاب می‌سازه، همه‌چی می‌سازه. نه که حسن خیکیه، بچه‌ها صداش می‌کنن: «حسن گامبو، سرت تو شامپو!» می‌خواییم با این دو نفر هم قهر کنیم بره. هی می‌آن در خونمون داد می‌زنن: «کاظم، بیا بازی، بیا بازی!» بازی چیه، آقا؟ بده بچه بازی کنه. رفوزه بشیم چه کار؟ دلم می‌خواد دکتر، مهندس، بازنشست، نیرو هوایی، هرچی شد بشیم، بریم پی کارمون بره. ولی تو خونه ما نمی‌شه درس خوند. تا می‌آم بشینم، باید پاشم برم نون بخرم، جارو کنم، خشتک زهرامونو بشورم. پارسال که رفوزه شدم، همه‌ش نیم نمره می‌خواستم قبول بشم. مدرسه‌مونم خیلی هردمبیه، آقا! بچه‌هاش دزدن، می‌آن دفترامونو می‌دزدن. سر کلاس یکی گچ پرت می‌کنه، یکی رو نیمکت ضرب می‌گیره، یکی پا می‌شه می‌رقصه. ما هم که می‌بینیم خر تو خره، حوصله‌مون سر می‌ره، از مدرسه جیم می‌شیم، می‌ریم فروشگاه بزرگ. اونجا پله‌برقی داره. می‌ریم می‌ایستیم خودمونو می‌زینم به اون راه. الکی نگاه می‌کنیم به جنس منس‌ها؛ یعنی مثلا ما هم اومدیم چیز بخریم. بعد می‌ریم سوار پله‌برقی می‌شیم، می‌ریم سواری می‌خوریم، عشق می‌کنیم. آقا، اجازه؟ سه تا دایی هم دارم، آقا! یکی‌شون دایی ضامن، یکی‌شونم دایی مرتضی. اونی که وضعش خوبه اسمش دایی رضوانه. یه وانت داره با یه اتوشویی. تا پامونو می‌ذاریم در دکونش، نامرد یه لگد می‌زنه در اونجامون، می‌گه: «بزن به چاک! باز اومدی از دخل کف ببری» به خدا تهمت می‌زنه، آقا! آقا، به خدا هیچکی به اندازه ما از دزدی بدش نمی‌آد. آقا، دایی مرتضی‌مون اولها کارگر بلورسازی بود، ولی وقتی من هنوز تو دل مادرم بودم، افتاد زندان. یه شب هفت نفر ریختن سرش، اون هم چاقو کشید، زد یکی‌شونو کشت. بعد دادگاه هم اومد بیخودی تقصیر رو گذاشت گردن دایی ما. قبل انقلاب از زندان اومد بیرون، رفت معتاد شد. حالا هم همیشه با زنش دعوا مرافعه داره. گاهی می‌ذاره از خونه‌ش می‌ره، می‌ره می‌ره پیداش نمی‌شه. بعد که برمی‌گرده، الکی به زنش می‌گه، رفته بودم بیمارستان ترک کنم. دایی مرتضی یه بچه کوچولو داره، هروقت می‌آد خونمون، می‌خواد از پله‌هامون بره بالا، بیاد پایین. ما هم می‌ریم دنبالش که نیفته سرش بشکنه. می‌ریم بغلش می‌کنیم. اونوقت می‌ترسه، سفت آدمو می‌گیره. دایی ضامن‌مون توی دولت آباد نفتیه، بعضی روزها که می‌ره نفت پخش کنه منو هم با خودش می‌بره. اون تا می‌ره نفت بده به خونه‌ها، بچه‌ها می‌گیرن مسخره‌م می‌کنن، می‌گن: «ای عرب پا نفتی، کی اومدی، کی رفتی؟» سنگ می‌زنن تو کله‌ام. من هم که زورم نمی‌رسه، گریه‌م می‌گیره. یه روز رفتیم در یه خونه نفت بدیم، اونوقت یه پسره بود - لال بود - دنبالمون کرد تا سر کوچه‌شون. فحش مادر داد، گفت: «دیگه در خونه ما نیا!» لال بود، آقا! نمی‌دونیم چی می‌گفت... آقا، هر وقت از مادرمون حرف می‌زنیم، بغض می‌آد گلومونو می‌گیره، ول‌مون نمی‌کنه... مادرمون سر بچه مرد، آقا! شب درد بچه گرفتش. رفتیم نبات خانومو آوردیم. نبات خانوم مامای محله‌س، شله، یه چشمش هم چپه. صبح که بچه اومد دنیا، مادرمون گذاشت از دنیا رفت. بچه‌ هم پشت سرش مرد، آقا!... مادرمون اون وقت که زنده بود، توی کارخونهٔ استارلایت کار می‌کرد. جوراب شلواری می‌بافت. وقتی شکمش اومد بالا، از اونجا بیرونش کردن. مادرمون اینقده سختی کشیده که خدا بگه، بس! همیشه مریض بود، بعضی وقتا هم غش می‌کرد. پاهاش قد یه متکا باد کرده بود، آقا!... آقا، باور کن، آقا... وقتی مادرمون مرد ما صد برابر الان بغض کردیم. من و زهرا و مصطفی شب تا صبح خوابمون نبرد. بابام اون شب هزار تا سیگار کشید،‌ ولی صبحش مادرمون مرد. وقتی رفتیم خاکش کنیم، ننه غلام نمی‌خواست بذاره ما بریم تماشا، می‌گفت، ما بچه‌ایم، گناه داریم. ولی من دزدکی توی مرده‌شور خونه هم رفتم. بوی بدی می‌ده مرده‌شور خونه، بوی گربهٔ مرده. آدم می‌خواد دل و روده‌شو بالا بیاره. وقتی مادرمونو اوردن گذاشتن توی سالن مرده‌شور خونه، هفت تا مرده زودتر مرده بودن. مادرمون نفر هشتم بود. مرده‌ها منتظر بودن دوش خالی بشه، سر نوبت برن تو، غسل کنن. جنازه یه دختر مدرسه هم بود. نمی‌دونی فک و فامیل دختره چی‌کار می‌کردن؛ یکی سرشو می‌زد به دیوار، یکی کفش‌شو دراورده بود می‌زد تو سر خودش. مادرمونو که اوردن بذارن توی قبر، سروکله‌ٔ مصطفی هم پیداش شد. مادرمون با مصطفی خوب بود. خدا بیامرز که رفت توی قبر، نمی‌دونم از کجا یه مگس اومد نشست روی کفنش. تا مصطفی کیش‌اش کرد، مگسه گذاشت در رفت. بعد شروع کردن با بیل خاک ریختن روی سر مادرمون. رباب خانم با ناخن صورتشو می‌کند. بابام داشت توی دل خودش گریه می‌کرد. اگه مصطفی نمی‌زد زیر گریه و توی خاک و خل غلت نمی‌خورد، من هم گریه نمی‌کردم... مادرمونو که خاک کردیم، دم قبرستان حلوای نذری پخش می‌کردن. واسه اینکه بوی گربهٔ مرده از دماغم بره، یه قاشق حلوا گذاشتم دهنم. ولی صاحب عذا که روشو برگردوند، تفش کردم. آقا، هیچی نمی‌تونستیم بخوریم. آقا، ما دلمون خیلی تنگه، هیشکی نیست ما را زفت کنه. دل‌مون می‌خواد از این دنیا می‌رفتیم. آقا، باورتون نمی‌شه، توی محله ما ملت تند تند می‌میرن، آقا! زهرامون یه همبازی داره، همقد خودشه. اسمش الهامه، پنج سالشه. ده بیست روز پیش باباش از داربست افتاد زمین عکس برگردون شد، مرد. دیروز الهام اومده بود خونه‌مون، یه عکس از باباش هم اورده بود، می‌گفت، هر شب خواب باباشو می‌بینه که اون دنیا آتیش درست کرده، می‌خواد بیاد بگیره اونو کباب کنه بخوره. یه حرفهایی می‌زد که مو به تن آدم سیخ می‌شد. اونوقت شب که خوابم برد، خوابیدم، خواب دیدم عزرائیل و شمر با آتیش اومدن بالای سرم، هی می‌چرخن و چه‌چه می‌خندن. عزرائیل نصفه‌س، آقا! یعنی پا نداره. من هم اومدم از دست‌شون در برم که دیدم یه خرگوشه داره با مامانش قایم موشک بازی می‌کنه. رفتم بگم، من هم بازی که گذاشتن در رفتن. من هم دنبالشون کردم. خسته که شدم دیدم سوار یه قایقم، یه سگ هم داشتم. داشتم با سگ بازی می‌کردم که یهو امیر ریزه پشت پا انداخت، افتادم توی آب. من هم رفتم سوار دوچرخه شدم، زدم به چاک. سگ هم از توی قایق پرید، اومد دنبالم. بعدش دیدم یه هلی‌کوپتر بالای سرمه، می‌خواد باید بستنی لیوانی‌مو قاپ بزنه. من هم با سنگ زدم شیشه‌شو شکوندم. اون هم ترسید در رفت، توی کوچه دباغ‌ها غیب شد. بعدش دیدم عباس آقا گرگ شده، می‌خواد بیاد زهرامونو بگیره لقمه‌ٔ چپش کنه. از ترسم دویدم توی پارک و رفتم سوار تاب شدم. اینقده تاب بازی کردم تا حسابی سرم گیج رفت. اومدم از تاب بپرم پایین، دیدیم زیر پام یه چاهه، یه چاه به این گندگی. داشتم ول می‌شدم ته چاه که از خواب پریدم. نشستم گریه کردم. اونوقت بابام بیدار شد، پرسید: «باز چی شده؟ شاشیدی؟» گفتم: «می‌ترسم.» گفت: «بگیر بخواب بابا تو هم دلت خوشه!» من هم لحافو که کشیدم روی سرم، همه‌ش خدا خدا می‌کردم ایم دفعه که خوابم برد، شانسم بگه، بزنه خواب خوشبختی ببینم، دلم خوش بشه. ولی اگه ما شانس داشتیم، آقا، اسم‌مونو می‌ذاشتن شانسعلی.
diff --git a/perf/texts/fa-words.txt b/perf/texts/fa-words.txt
new file mode 100644
index 000000000..4937544d8
--- /dev/null
+++ b/perf/texts/fa-words.txt
@@ -0,0 +1,10000 @@
+در
+به
+از
+ویکی‌پدیا
+که
+را
+این
+با
+است
+رده
+برای
+کاربر
+بحث
+تصویر
+میلادی
+ایران
+تاریخ
+نام
+پرونده
+آن
+یک
+ساعت
+صفحهٔ
+کنید
+پیوند
+مقاله
+صفحه
+شما
+اصلی
+عنوان
+یا
+تا
+سال
+هم
+من
+استفاده
+بر
+خود
+شده
+شد
+تغییرمسیر
+شهرستان
+کار
+راهنمای
+اگر
+تکثیر
+چه
+ویرایش
+حق
+مقاله‌های
+می
+فارسی
+نیست
+دیگر
+نوشتن
+پنج
+بود
+زبان
+سیارک
+امضا
+کمک
+شیوه‌نامه
+منابع
+ملی
+ثبت
+آثار
+پانویس
+۱۱
+میز
+خودآموز
+بخش
+دارد
+خرد
+انگلیسی
+او
+لطفاً
+نیز
+۱۵
+شماره
+پهنا
+بنیاد
+استان
+هر
+اثر
+می‌شود
+مورد
+کرد
+یادکرد
+امیدوارم
+راهنما
+کنیم
+خوش
+ویکی
+چیزی
+پس
+شهر
+پیش
+فهرست
+مرجع
+خط
+آمدید
+اطلاعات
+اینجا
+تاریخی
+زیر
+منبع
+جعبه
+جدید
+دوره
+بیشتر
+اینکه
+بهتر
+یکی
+شود
+دو
+سپتامبر
+راهنمایی
+پیوندهای
+حذف
+۲۰۰۰
+خوب
+نظر
+آزاد
+قرار
+خواهد
+تمرین
+باشد
+بله
+پیرامون
+سلام
+آموزش
+اصل
+۱۰
+نه
+صفحات
+۱۹
+۱۲
+۲۰۱۱،
+های
+پاس
+ولی
+توسط
+چگونه
+برگزیده
+بداریم
+فقط
+ویکی‌پروژه
+۲۰۰۱
+روی
+سریع
+اکتبر
+صورت
+دست
+قهوه‌خانه
+۱۴
+دانشگاه
+بنیادی
+اما
+بیاید
+ناشر
+داشتید،
+باید
+بروید
+الگو
+چهار
+اول
+مارس
+کتاب
+ایجاد
+بازدید
+توجه
+آنها
+پایه
+۲۰
+کشور
+ساختار
+سخ
+خوش‌آمدید
+مقالهٔ
+شده‌است
+سازمان
+فارسی‌نویسی
+بودن
+مرکزی
+باز
+آمریکا
+وب
+۱۶
+نویسنده
+کادر
+دسامبر
+صورتی
+۲۰۰۷
+۱۸
+۲۰۱۰،
+کند
+فنی
+تصمیم
+۱۳
+تهران
+وجود
+۱۷
+نشانی
+چطور
+چند
+کشف
+اوت
+دانشنامه‌ای
+فوتبال
+علمی
+۲۰۰۸،
+درج
+۲۰۰۲
+هستند
+بگیرید
+۲۱
+۲۰۱۱
+نوامبر
+مطالب
+آزمایش
+وی
+کاربران
+فیلم
+ها
+ماندن
+مقالات
+بپرسید
+حروف
+لذت
+جمعیت
+بحثم
+ببرید
+خوشتان
+مدک
+وابسته
+ویکی‌پدیانویس
+ویکی‌پدیانویسان
+۲۰۰۹،
+اسلام
+۲۲
+مسایل
+آوریل
+بنویسیم
+۱۹۹۹
+کاربری
+علامت
+واقع
+شوید
+اهمیت
+۲۳
+کلاس
+کردن
+ای
+آشنا
+باشید
+نگاهی
+کوچک
+نکنید
+وب‌گاه
+پروژه‌های
+کرده
+۲۸
+می‌توانید
+انتخاب
+مکنید
+بعد
+روز
+است،
+جستارهای
+شدن
+نوع
+نمونه‌های
+۲۴
+نفر
+دارید،
+بیندازید
+خودکار
+۲۰۰۶
+نوشته
+مطالعهٔ
+انبار
+عجله
+غفلت
+فهرست‌شده
+مشارکت
+اهل
+۲۵
+سوال
+محمد
+بوده
+۳۰
+بسیار
+بزرگ
+میراث
+میان
+زمان
+منابعی
+اثبات‌پذیری
+جلالی
+سیارک‌های
+دهستان
+مرکز
+انجام
+فوریه
+می‌کند
+۲۶
+نام‌های
+ما
+یعنی
+ایرانی
+ژوئن
+غیر
+پایان
+یونسکو
+حال
+پرحجم
+چپ
+می‌گویم
+داشته
+جمله
+پیام
+عمومی
+گردشگری
+قبل
+همین
+همچنین
+همان
+مالک
+سپاسگزارم
+سال‌های
+همه
+اندازه
+مربوط
+ویکی‌انبار
+قدر
+چون
+بیرون
+ویکی‌نویسی
+داده
+کسب
+دوم
+ویژه
+هیچ
+فرهنگ
+کسی
+بروید،
+تنها
+۲۰۰۳
+دارای
+ساخت
+افراد
+رتب
+تازه‌واردان،
+مه
+محلی
+بصب
+بین
+پتوپ
+مقاله‌ها
+نیازمند
+اسلامی
+۲۷
+بی
+مرگ
+علی
+۲۰۰۵
+متون
+مطلق
+سه
+می‌باشد
+نیاز
+شرکت
+۲۹
+۲۰۰۹
+باشگاه
+دلیل
+زندگی
+چاپ
+موجود
+۲۰۰۸
+نقل
+گروه
+۲۰۰۴
+انتهای
+دارند
+محتویات
+شاد
+موضوعات
+جستجوی
+۱۹۹۸
+مردم
+نشان
+موسیقی
+ویکی‌مدیا
+همراه
+ویکی‌گفتاورد
+تپه
+شورای
+دانشنامه
+ویکی‌واژه
+بدون
+مانند
+راه
+شهرهای
+فرهنگی
+سیاره
+ویکی‌نبشته
+ترجمه
+فراویکی
+حجم
+کنونی
+طبق
+ژانویهٔ
+بار
+اجرام
+روستای
+ویکی‌نَسک
+تغییر
+خوشامد
+سرعت
+۲۰۱۲،
+جنگ
+برابر
+محل
+سر
+سپس
+سیارک‌ها
+عربی
+بازیابی
+داشت
+بازی
+ماه
+می‌تواند
+رو
+کنید،
+ژانویه
+معرفی
+بنا
+مشترک
+چندین
+دوران
+ندارد
+جهان
+حقوق
+کنم
+بالا
+ضمن
+داد
+وبگاه
+البته
+آب
+قدیمی
+امکان
+جمهوری
+قسمت
+۰۹
+مفیدند
+پیدا
+وپ
+پروژه
+بن
+همکاری
+۰۸
+تغییرات
+كه
+منطقه
+معماری
+چم‌وخم
+معرفی‌شده
+کنند
+هزار
+عرض‌جغرافیایی
+طول‌جغرافیایی
+۰۷
+روی‌نقشه
+برخی
+آی‌پی
+آمار
+ویکی‌پدیای
+۲۰۱۰
+جای
+موضوع
+تمام
+گرفته
+شرقی
+فوریهٔ
+اخیر
+قمری
+متوسط
+دیگری
+غربی
+درگاه
+ربات
+راستی
+اولین
+۳۱
+باستانی
+امنیت
+چنین
+آلمان
+کم
+رسمی
+جهانی
+مطالعه
+بررسی
+ژوئیه
+فعالیت
+آغاز
+آذربایجان
+فکر
+اين
+الگوی
+تیم
+لطفا
+ژوئیهٔ
+صنایع
+درود
+نامه
+تلفن
+اقدام
+روستا
+ایشان
+می‌کنند
+فارس
+حتی
+تعداد
+دربارهٔ
+فعلی
+درست
+مدیران
+گفتگو
+حجت
+دستی
+ستاره
+بسیاری
+اند
+نقش
+کلیک
+بودند
+۰۶
+تولد
+کردم
+زادگان
+شاه
+متحده
+توضیح
+طول
+دوست
+ذکر
+رسیده
+مقاله‌ای
+قابل
+اضافه
+مسائل
+ایالات
+همهٔ
+اینترنتی
+نام‌گذاری
+سیاسی
+طور
+خیلی
+رضا
+روستاهای
+چپ‌چین
+تولید
+صفحه‌های
+برچسب
+خانه
+شکل
+دولت
+می‌توان
+شامل
+می‌نویسید
+یادتان
+موسسه
+جنوب
+نرود
+نشریه
+باشند
+۰۰
+آمد
+وارد
+فرانسه
+جوایز
+مجموعه
+قانون
+به‌عنوان
+متن
+۰۵
+جایزه
+خبری
+سید
+ویکی‌خبر
+گفته
+اساس
+سیاست‌های
+جنوبی
+سایت
+آری
+ممکن
+نمی
+بنویسید
+روسیه
+فیلم‌های
+مهٔ
+سوم
+تشکر
+جام
+۱۳۸۵
+حدود
+کامل
+عرض
+شمارهٔ
+قاجار
+ماني
+عکس
+اجازه
+تصحیح
+آرش
+علوم
+نظری
+جای‌های
+اشاره
+دانشنامهٔ
+گرفت
+کردند
+جان
+فرهنگی،
+مختلف
+بانی
+توضیحات
+ارتفاع
+موارد
+میلاد
+مثل
+مرمت
+ژورنال
+شعر
+محتوای
+بیش
+چرا
+شمال
+خواهر
+می‌کنم
+خم
+فصل
+شروع
+تشکیل
+چم
+سرشماری
+دهه
+مشکل
+ساخته
+زبان‌ها
+گونه‌های
+مدت
+مجموعه‌ای
+زیادی
+بهترین
+درباره
+موافق
+دیرینگی
+نتیجه
+هست
+آلبوم
+ادامه
+جهت
+خراسان
+شرح
+ایران‌شهر
+زیستی
+پیشرفته
+می‌دهد
+راهنماهای
+صفحه‌ی
+افغانستان
+هماهنگی
+قلعه
+اصفهان
+بالای
+جغرافیایی
+شخصی
+نسبت
+می‌شوند
+تصنيف
+مطرح
+عناوین
+بوده‌است
+۰۱
+۱۳۸۶
+زمین
+سازی
+حزب
+سی
+آن‌ها
+سرشناسی
+انقلاب
+مي
+واژه‌ها
+مهم
+سایر
+می‌آید،
+دکتر
+مساحت
+قطعنامه
+۰۴
+شدند
+مرد
+درگذشتگان
+پرونده‌های
+باعث
+نکاتی
+اعلام
+نامگذاری
+پروژه‌ای
+زبانه
+سیستم
+انتفاعی
+یادداشتی
+کتابچه
+پرسیدن
+۰۳
+چندرسانه‌ای
+قول‌ها
+هرکسی،
+ویکی‌گونه
+خوانندگانش
+کیلومتر
+سطح
+زمینه
+اهالی
+سؤال،
+حسین
+اصطلاح‌نامه
+موقت
+سندباد
+بود،
+تبدیل
+سبک
+بنویسیم؟
+روش
+میثم
+زمانی
+۱۳۸۷
+دسترسی
+کد
+انگلستان
+برنامه
+رنگ
+تحت
+هاروارد
+مدیر
+امیروبات
+جرم
+جلد
+وقتی
+گودال
+نگاره
+شمالی
+۰۲
+پاسخ
+آیا
+تر
+منتشر
+شوند
+انتشارات
+مخالف
+مسجد
+بایگانی
+هماهنگ‌کننده
+کپی
+متر
+مجلس
+۴۰
+دهید
+شاید
+آنجا
+گل
+کاربرهای
+ناسا
+دوستان
+جناب
+پیشنهاد
+ان
+دی
+یافت
+آسمانی
+۱۳۸۸
+هنوز
+نخستین
+مذهب
+نویسندگان
+زنده
+ایالت
+ماسه‌بازی
+احمد
+آنهاست
+کنار
+شبکه
+بازی‌های
+مشخص
+ژاپن
+نمود
+وقت
+کشورهای
+خواندن
+معروف
+اروپا
+اشتباه
+کرمان
+سن
+معرف
+پهلوی
+درجه
+سوی
+ام
+محیط
+بحثتان
+روزنامه
+گونه
+۱۹۹۷
+طرف
+کل
+داستان
+علت
+الگوهای
+آمریکایی
+تو
+آمده
+بین‌المللی
+داتک
+امیر
+انتشار
+قوانین
+شماره‌دار
+دادگان
+موفق
+رشته
+خاطر
+دارم
+خورشیدی
+حسن
+معنی
+زنان
+انتقال
+پی
+حکومت
+لازم
+به‌آفرید
+تپه‌های
+نام‌صفحه
+شابک
+زن
+قرن
+دهد
+عمل
+بازیگر
+تصاویر
+رئیس
+ممنون
+عزیز
+یاد
+گفت
+هفته
+دین
+رای
+وضعیت
+فرار
+درخواست
+سیاست
+سمت
+حالت
+پسر
+کوه
+پرچم
+طی
+ادبیات
+الله
+کلی
+کشف‌شده
+بازیابی‌شده
+غرب
+فرودگاه
+۱۳۹۰
+سپاس
+واژه
+توابع
+ابعاد
+کمربند
+دور
+مدرک
+مبدا
+مازندران
+کننده
+مدیریت
+دوستدار
+وجه
+مهدی
+نمایش
+هجری
+هنر
+ابتدا
+ده
+رسید
+اعضای
+انسان
+امام
+مثال
+دادن
+آخرین
+اسرائیل
+قول
+نمایید
+حضور
+رود
+خودتان
+زیاد
+جا
+توصیه
+مناطق
+عراق
+مطلب
+پرسش
+خان
+عضو
+حسام
+حداقل
+باستان
+ارائه
+۵۰
+مواد
+کمی
+خارج
+دما
+چین
+وزارت
+اوج
+خروج
+طبیعی
+پزشکی
+ستاره‌شناسی
+فراموش
+پایین
+کاری
+اکنون
+بعضی
+میانگین
+نشده
+هزاره
+نشر
+مهندسی
+شد،
+آباد
+خودم
+اسپانیا
+خاص
+دوران‌های
+۱۳۸۹
+جریان
+منظور
+طریق
+ترتیب
+بناهای
+بیان
+دارید
+روستایی
+سطحی
+شیخ
+نسخه
+حرکت
+بنده
+سده
+اجتماعی
+طراحی
+حرف
+خودروهای
+ویکی‌گزارش
+نو
+هند
+استاد
+به‌شما
+دوباره
+توان
+نظامی
+بلکه
+سری
+همسر
+هنری
+شیراز
+مفیدی
+جمع
+علم
+خانواده
+انتخابات
+آلمانی
+فاصله
+نیروی
+مرتبط
+نمونه
+پدیا
+فرمایید؛
+شناخته
+چگالی
+دیده
+معتبر
+مناسب
+قرآن
+میلیون
+واحد
+۴۵
+مهر
+تبریز
+هنگام
+گسترش
+طبقه‌بندی
+۱۹۹۶
+فلسفه
+کرمانشاه
+گردید
+گذشته
+دنیا
+زیرا
+قدرت
+مثلا
+ببینید
+لیگ
+دریافت
+انحراف
+نام‌رسمی
+می‌آید
+حمله
+گرانش
+توسعه
+افزایش
+چشم
+مکان
+عدد
+ابهام‌زدایی
+دانش
+موضوعی
+نزدیک
+شخص
+آنان
+دیگران
+بازیکنان
+آقای
+کاشف
+تلویزیونی
+زاده
+بسته
+جایی
+خدا
+حاضر
+شرق
+می‌شد
+حساب
+پدر
+داشتید
+نقض
+پیش‌شماره
+ایتالیا
+کاربرد
+سعی
+رفت
+برد
+‌بودن
+کاربردها
+تناوب
+۳۵
+معمولاً
+زبان‌های
+بهمن
+۳۲
+عباس
+حضیض
+پدیدآور
+انجمن
+فیزیک
+نگاه
+فعال
+نور
+نسخه‌ها
+ریاست
+هستم
+فلکی
+فرد
+مسیر
+اجازه‌نامه
+جامعه
+آلبدو
+مصر
+آنومالی
+کلمه
+نیم‌محور
+بریتانیا
+۱۹۹۵
+پر
+پاک
+۱۹۹۳
+بازیگران
+بخشی
+فرانسوی
+داخلی
+خبر
+سئوال
+محمود
+باشد،
+امروز
+کرده‌است
+ارتباط
+درصد
+تاریخچه
+ملل
+اصلاح
+معیارهای
+همچون
+طرح
+شده‌اند
+هدف
+عالی
+وقایع
+میدان
+محسوب
+حل
+باغ
+استان‌های
+خودش
+قطع
+ایران،
+۳۳
+۳۴
+اش
+دنبال
+شهری
+تعریف
+دانشکده
+انواع
+دار
+ورزشگاه
+نقشه
+کوتاه
+شمار
+مدرسه
+کمتر
+آرامگاه
+عصر
+عبارت
+بیست
+تن
+خرابکاری
+المپیک
+تیر
+می‌رود
+خیابان
+بازار
+نامزد
+میرزا
+داخل
+اندازه‌تصویر
+پایگاه
+رضوی
+سؤال
+۱۹۹۰
+الان
+گرامی
+نبود
+خوبی
+۳۷
+خارجی
+گیری
+آورد
+برچسب‌تصویر
+۴۸
+سیستان
+۱۹۹۴
+آزادی
+رشد
+نباید
+پرسشی
+۱۳۸۴
+حد
+۳۶
+ملیت
+رشدجمعیت
+تازه
+میانگین‌دما
+عدم
+نیروهای
+تراکم‌جمعیت
+سؤالی
+نام‌های‌قدیمی
+بنابراین
+ارتش
+شب
+داشتن
+علاوه
+ابن
+شمارروزهای‌یخبندان
+میانگین‌بارش‌سالانه
+پل
+تصویب
+میانه
+خرداد
+گیلان
+سنگ
+کنترل
+بهزاد
+کیفیت
+می‌‌نویسید
+۴۱
+درگذشت
+علیه
+گزارش
+شیعه
+خور
+۳۸
+جزیره
+ره‌آورد
+دسترس
+دستگاه
+نام‌محلی
+تگزاس
+جز
+همیشه
+۴۲
+اجرا
+کوشش
+پخش
+رد
+۴۶
+متحد
+اسفند
+وزیر
+خواننده
+بهبود
+اثبات
+سفید
+نظرخواهی
+شرایط
+جمله‌خوشامد
+ترکیه
+۴۴
+همدان
+قم
+۳۹
+می‌گیرد
+۴۳
+بلوچستان
+چیز
+دسته
+خوزستان
+گنو
+ترانه
+کدام
+خودرو
+۵۵
+۴۷
+باقی
+بندی
+۵۱
+بخوانید
+۱۹۹۲
+خواهند
+صد
+ناحیه
+۵۳
+کاهش
+۱۹۹۱
+میشود
+مذهبی
+۴۹
+ساختمان
+اولیه
+مقابل
+۵۲
+سبز
+وحید
+۵۷
+مشهور
+متوجه
+تهیه
+کافی
+آنچه
+ترک
+افزودن
+می‌شود،
+جدا
+۱۳۸۲
+چهارم
+تقسیم
+نژاد
+معنای
+کشاورزی
+صفوی
+براساس
+سیاه
+هایی
+آسیا
+تمامی
+تحقیق
+۱۹۶۰
+ساسانیان
+نوشتار
+رادیو
+۵۶
+۵۴
+اسم
+ارزش
+دهانه
+اقتصادی
+ابراهیم
+نخست
+فرزندان
+۵۹
+هاي
+شهرها
+دقیقه
+حالا
+دستور
+امور
+رابطه
+پارک
+جنبش
+دختر
+قالب
+بیماری
+نام‌های‌دیگر
+محوطه
+بازیکن
+کشته
+دارد،
+مشهد
+منتقل
+شهریور
+مرداد
+کیلومتری
+پرداخت
+۵۸
+تخصصی
+۲۰۱۲
+مرده
+دهیار
+صنعتی
+خدمت
+پشت
+فشار
+می‌کرد
+تلاش
+مدیاویکی
+تلویزیون
+میزان
+سال‌بنیاد
+قبلی
+انرژی
+بدست
+نظام
+حوزه
+پا
+بودم
+یزد
+هفت
+ازدواج
+است؟
+فضای
+نظریه
+اختلاف
+حمایت
+خواهم
+مجله
+رفته
+اجرای
+می‌گردد
+برتر
+متولد
+کره
+خاک
+برگزار
+سرزمین
+بدن
+کرده‌اید
+مسابقات
+اقتصاد
+ندارم
+بعدی
+قبول
+خلیج
+آخر
+کمیته
+فروردین
+مادر
+کارگردان
+می‌کنید
+سال‌ها
+کسانی
+مصرف
+جدول
+جشنواره
+آنرا
+دید
+فرزند
+عرب
+کاملا
+آمل
+پادشاه
+دیدگاه
+آذر
+اشکانیان
+سفر
+متفاوت
+وزن
+نیویورک
+داشتند
+بیشتری
+موزه
+یه
+می‌رسد
+خاصی
+دل
+دهستان‌های
+آنکه
+استقلال
+پنهان
+مجوز
+نوعی
+کردید
+لرستان
+جغرافیا
+ترکی
+محسن
+هوایی
+۱۹۸۱
+فروش
+مقام
+مقدار
+۱۶۱۵
+قزوین
+حالی
+عمر
+لزوم
+میل
+آبی
+دقت
+اصلا
+اطلاع
+رخ
+شکست
+اعمال
+اینترنت
+موتور
+دومین
+شهید
+تحقیقات
+تاسیس
+برخورد
+روم
+ماده
+محله
+لینک
+راست
+امروزه
+کرده‌اند
+بازگشت
+جواب
+پارس
+یونان
+رتبه
+شده،
+۱۳۸۱
+اساسی
+نقطه
+گردد
+موجب
+سخن
+تقویم
+نکته
+می‌دهند
+مستقل
+جامع
+اردیبهشت
+هستید
+سینما
+مدل
+کانادا
+گاه
+آورده
+حفظ
+ثابت
+احترام
+بوشهر
+مربع
+۱۹۸۸
+روابط
+سیمرغ
+درون
+زیرنویس
+کن
+نظرم
+ترکیب
+بهار
+بد
+پادشاهی
+دلار
+شیمی
+تعیین
+بابل
+نفت
+دولتی
+مدتی
+نظرات
+درستش
+کاتالوگ
+گاهشماری
+لحاظ
+ساده
+بخش‌های
+شوروی
+باب
+بی‌بی‌سی
+گرفتن
+دادم
+مثلاً
+گروه‌های
+ندارند
+کردستان
+حاصل
+شود،
+انسانی
+گرم
+روشن
+مسکن
+خون
+۱۳۸۰
+رسیدگی
+مفهوم
+خمینی
+گیاهان
+ساز
+آهنگ
+ترین
+هرمزگان
+۱۹۸۹
+صاحب
+کارهای
+اغلب
+عبدالله
+مشغول
+۱۰۰
+شناسی
+محمديان
+گفتم
+مختصات
+دهند
+یونانی
+رایانه‌ای
+یکم
+ستارگان
+کتاب‌های
+ایرانیان
+آوردن
+صنعت
+کند،
+صحبت
+فناوری
+نمی‌شود
+آینده
+واگردانی
+کتابخانه
+برجسته
+امر
+نقد
+مخصوص
+بزرگی
+آبان
+نتایج
+براي
+یافته
+لقب
+متاسفانه
+مالکیت
+مشاهده
+عرضه
+کارت
+گاهی
+شش
+دفاع
+مایکل
+اداره
+خبرگزاری
+دره
+مسئله
+صحیح
+ولایت
+گروهی
+رودخانه
+مقدس
+مراسم
+کشورها
+باد
+تاکنون
+خلاف
+علاقه
+ارومیه
+مرحله
+ورود
+۲۰۰۷،
+تکمیل
+موقعیت
+رویدادها
+تفاوت
+ایستگاه
+شیمیایی
+مگر
+ضد
+ژاپنی
+استاندارد
+دریای
+۱۹۸۰
+معاصر
+زندان
+غیرقابل
+عملیات
+دریایی
+خصوص
+برخوردار
+لندن
+شیوه
+آقا
+مشابه
+سخت
+خلاصه
+دفتر
+برنده
+سنت
+پاپ
+جلوگیری
+قدیم
+ورودی
+اسکار
+بطور
+چر
+بندر
+مرا
+راک
+نیشابور
+نیستند
+۱۵۱
+مشکلی
+آتش
+کشوری
+تابستانی
+امپراتوری
+بررسی‌های
+آن،
+اس
+میکنم
+پارسی
+تشخیص
+شاعر
+خدمات
+عهده
+نیمه
+مشکلات
+نیست،
+آشنایی
+بصورت
+تأسیس
+درمان
+ابزار
+آموزشی
+نوروز
+بروجرد
+تواند
+قتل
+تحصیل
+دیدم
+مدرس
+دانشگاه‌های
+جمهور
+محدود
+برج
+آبشار
+دانشجویان
+احتمال
+رفتار
+اعتماد
+اطراف
+هشدار
+همواره
+قطعنامه‌های
+محمدرضا
+پاریس
+ساله
+کالیفرنیا
+وسیله
+اصول
+درخت
+سالگی
+۱۹۷۷
+پیشه
+داریم
+شخصیت
+قصد
+نداشته
+می‌گوید
+جشن
+ویرایش‌های
+ادبی
+بهره
+سنتی
+فوق
+کنید؛
+تام
+بانک
+دهم
+استرالیا
+دقیق
+نامیده
+نفوس
+فراهم
+می‌توانند
+بدین
+اختیار
+چشمه
+دادند
+يا
+اردبیل
+پست
+خانوار
+قهرمانی
+منصور
+سرخ
+روسی
+۱۳۸۳
+شبیه
+بشر
+قرمز
+قطر
+سبب
+کشتی
+برده
+صدا
+یکسان
+شمسی
+مجدد
+اکثر
+جالب
+تک
+گلستان
+پنجم
+فراوان
+يك
+نرم‌افزار
+توهین
+اتحادیه
+عشق
+ظهیری
+گورستان
+بلژیک
+بکار
+رستم
+سرشناس
+‌ها
+هیئت
+علیا
+مقالاتی
+رباتیکی
+هنگامی
+لطف
+بختیاری
+روح
+ارجاع
+تقریبا
+۱۹۷۳
+سپاه
+‌های
+یکدیگر
+نموده
+رمان
+کرد،
+جنسی
+بزرگترین
+پیشرفت
+دعوت
+بقیه
+کلمات
+شهرت
+مرکزی،
+رایانه
+یمن
+تخت
+معادل
+صادق
+وسط
+خوانندگان
+تلفظ
+اتفاق
+امامزاده
+تحصیلات
+خانوادگی
+حقیقت
+خورشید
+نوری
+نقاط
+پایتخت
+بند
+گوگل
+مانده
+نزدیکی
+سعید
+امید
+نشود
+نر
+مسعود
+سلطان
+ادغام
+سفلی
+دریا
+لاتین
+اجماع
+خوانده
+سابق
+ریاضی
+درستی
+فضایی
+دلایل
+برندگان
+بعدها
+متعلق
+پیشین
+شدم
+هنرمند
+درس
+ذخیره
+کارگردانی
+نباشد
+دانقولا
+اون
+تابع
+مالی
+صدای
+بلند
+بارگذاری
+بخش‌ها
+اینگونه
+اواخر
+ریشه
+نشد
+کاخ
+ریز
+فرض
+قانونی
+برق
+جلوی
+کودکان
+نزد
+قاسم
+آهن
+زنجان
+نگارش
+شدت
+می‌گویند
+جایگزین
+جاده
+می‌کردند
+مفید
+زرشک
+لیست
+محور
+ویکیپدیا
+رایج
+مناسبت‌ها
+خلق
+مراکز
+ساری
+عامل
+نقاشی
+رسیدن
+کارشناسی
+۱۹۸۴
+زده
+رعایت
+انگلیس
+اطلاعاتی
+ورزشی
+مقایسه
+منبعی
+بازبینی
+حافظه
+حتما
+عربستان
+مستقیم
+گیرد
+الدین
+۱۹۸۲
+علیرضا
+تعدادی
+ورزش
+برادر
+گذاشته
+تهران،
+محصولات
+زندگینامه
+هوا
+۱۹۸۶
+۶۰
+کس
+پوشش
+حکم
+قهرمان
+خانه‌های
+حاج
+خواهش
+گردآفرید
+نوبل
+نرم
+رهبری
+خیر
+تجاری
+نوشت
+۱۹۸۵
+جوان
+واقعی
+نظیر
+سند
+سرانجام
+منجر
+اعداد
+فی
+واقعا
+نبرد
+مردان
+جغرافیای
+شدید
+روند
+ویرایشی
+دشت
+رده‌بندی
+پرحجم،
+گذاری
+افشار
+۱۹۷۸
+زدن
+سوئد
+خویش
+ماهی
+خالی
+درآمد
+آمریکای
+مسلمانان
+کجا
+می‌باشند
+طوری
+اید
+دکمهٔ
+احمدی
+درد
+۱۹۸۷
+شاعران
+گویا
+نداشت
+هـ
+سالهای
+ششم
+شیر
+دچار
+تاثیر
+زیست
+دینی
+سریال
+نماد
+راجع
+مطالعات
+مراجعه
+لحن
+خطر
+پرسپولیس
+حضرت
+مکتب
+دامنه
+بروید؛
+زیبا
+بافت
+مسلمان
+کامیار
+محافظت
+ناوبری
+نهایت
+کلیسای
+هشت
+تکرار
+پرورش
+توزیع
+معمولا
+وبلاگ
+طولانی
+تجربه
+ظاهر
+گسترده
+ممنوع
+پیروزی
+چهل
+گاز
+عکاسی
+کاملاً
+احساس
+همچنان
+تفسیر
+چک
+مترجم
+مشخصات
+اینها
+تایید
+۱۹۷۹
+توکیو
+ال
+سمنان
+۲۰۰
+رهبر
+بیت
+سومین
+خورده‌است
+پاکستان
+۹۰
+همانند
+فردی
+ملحق
+کامپیوتر
+سوریه
+پدرش
+اوایل
+پول
+سوره
+تقویم‌های
+آفریقا
+کتاب‌ها
+دنیای
+همانطور
+دودمان
+هدایت
+باره
+سلسله
+موسوی
+قضیه
+غیره
+صرف
+آید
+ايران
+پک
+طبقه
+حاکم
+داریوش
+گوناگون
+زهرا
+اسماعیل
+زمین‌لرزه
+اعتبار
+بعنوان
+مُروا
+توانست
+۱۳۷۹
+تدوین
+اهواز
+سبزوار
+جکسون
+نمایندگان
+مقاومت
+آی
+برداشت
+گشت
+قلم
+تنظیم
+نگاری
+هلند
+باور
+نهاد
+سینمای
+تمدن
+فرهنگستان
+کردی
+ویندوز
+سوئیس
+کانی
+نویسی
+ممتنع
+مانی
+پشتیبانی
+جو
+رده‌ها
+ساکن
+شهرک
+روزی
+صحنه
+اصطلاح
+تئاتر
+جستجو
+جلو
+فردا
+جیمز
+کی
+هرگز
+چیست؟
+حمل
+توصیف
+گیتار
+ری
+والدین
+۱۹۷۶
+حفاظت
+رشت
+سابقه
+کودک
+کنون
+فعالیت‌های
+عوض
+اعتراض
+نسل
+دریاچه
+مرز
+باشگاه‌های
+کهگیلویه
+میکند
+دادگاه
+تصویری
+خانم
+مخالفت
+نصب
+آل
+افرادی
+چاه
+نماینده
+نگه
+عملکرد
+جدیدی
+۱۹۷۰
+مهمترین
+آمده‌است
+محمدعلی
+بدهید
+اتحاد
+شرکت‌های
+موج
+رم
+کشیده
+تحلیل
+نظارت
+تابلوی
+شهرداری
+محصول
+متعدد
+نماید
+قوم
+مصطفی
+جزایر
+گرمی
+عقب
+صلح
+شعار
+ارسال
+جی
+نوشته‌های
+غلط
+۱۹۷۱
+سازنده
+نکرده
+مواردی
+جوانان
+حمام
+دورهٔ
+تبریک
+بگذارید
+دانشگاهی
+مس
+ماند
+خداوند
+مهاجرت
+ضبط
+ست
+احتمالا
+لبنان
+دوربین
+خودشان
+عبور
+ارشد
+بنام
+فرمان
+عبارتند
+مطابق
+خرم‌آباد
+بالاتر
+سد
+تقریباً
+اکبر
+دیدن
+موفقیت
+مدرن
+نگهداری
+۷۰
+عوامل
+پای
+جایگاه
+۸۰
+زادروز
+پرواز
+خلیفه
+هفتم
+ماشین
+هرچند
+هسته‌ای
+عناصر
+اسناد
+گنبد
+لا
+نهایی
+تدریس
+طلایی
+زابل
+چندان
+اروپایی
+ظاهری
+صفر
+اول،
+اشعار
+دبیرستان
+معلوم
+برنامه‌های
+نخواهد
+زد
+بیفزایید
+خصوصی
+وظیفه
+ادعا
+عزیزی
+عمده
+انتظار
+آن‌لاین
+قبلا
+مبارزه
+هستند،
+خسته
+فرصت
+رفتن
+مشارکت‌ها
+گرامی،
+سراسر
+۱۹۸۳
+پیروز
+گویش
+رفع
+جزو
+گفتاورد
+متال
+مکزیک
+۱۳۵۷
+امپراتور
+اطلس
+اسپانیایی
+پنجاه
+شاپا
+بیمارستان
+پیامبر
+بستک
+می‌کنیم
+اشکال
+تقسیمات
+الکتریکی
+درک
+سلطنت
+لباس
+دهنده
+نشست
+اعدام
+اقوام
+شاخه
+سلام،
+الگوریتم
+چپچین
+شان
+خواست
+مدال
+امارات
+جبهه
+باشم
+مطبوعات
+مستعار
+نیازی
+عادی
+چینی
+افتخار
+کهن
+نا
+مثبت
+شخصیت‌های
+خطوط
+ویلیام
+سلطنتی
+منطقی
+اطمینان
+جعفر
+سقوط
+روزهای
+گرفته‌است
+طبیعت
+باشیم
+رده‌های
+ترتیب‌پیش‌فرض
+شبه
+موافقم
+یهودیان
+تربیت
+دیوید
+معاون
+پرندگان
+ملت
+دیوان
+تی
+پلیس
+ملک
+نيز
+هنرمندان
+عین
+تماس
+حرفه‌ای
+آستانه
+بماند
+واکنش
+زحمت
+عمان
+حافظ
+نیم
+منفی
+آسیای
+تابستان
+جدی
+قابلیت
+ساختن
+آسیایی
+رجوع
+شهرستان‌های
+معین
+نیستم
+ناشی
+تهیه‌کننده
+داشته‌است
+دانشمندان
+صبح
+اعتقاد
+مبارک
+سورنا
+اساطیر
+اصلاً
+تذکر
+خطی
+کاربردی
+داشتم
+آدم
+کتابی
+مختلفی
+کاربرانی
+سرباز
+جذب
+متغیر
+وضع
+روزبه
+مجازی
+گذاشت
+بابت
+اعلانات
+مهمی
+فلان
+آماده
+مصاحبه
+باتجربه‌تر
+رقص
+کلاسیک
+گیاه
+سامانه
+مجبور
+نحوه
+نبوده
+نفوذ
+متری
+کانال
+حیات
+گفتمان
+جلسه
+ارادتمند
+درفش
+حومه
+تصور
+خاندان
+بهرام
+لحظه
+برزیل
+یهودی
+دهخدا
+ایتالیایی
+رسانه
+۱۹۷۵
+مسابقه
+خواستم
+کابل
+نی
+اوکراین
+موسی
+شما،
+بگیرد
+زرد
+هوای
+فلسطین
+اهداف
+است؛
+ولسوالی
+غار
+بنای
+نوشتارهای
+مربوطه
+اخبار
+بودند،
+مهم‌ترین
+سینمایی
+پیمان
+۸۸
+همزمان
+ها،
+احتمالاً
+آسمان
+شهرک‌های
+ابتدای
+ندهید
+بوجود
+آیدا
+جانوران
+سده‌های
+بازداشت
+هسته
+یادداشت
+ایلام
+نامی
+مجموع
+هنرهای
+می‌دانند
+ادعای
+سرویس
+بگویم
+ظهور
+هزینه
+کاویانی
+الگوها
+ضروری
+آرام
+حذفی
+اقیانوس
+یی
+امتیاز
+زمینی
+آدرس
+باشه
+امکانات
+بیشترین
+طراح
+نواحی
+مطالبی
+مقالات،
+بخاطر
+لی
+آفتاب
+بفرمایید
+دقیقا
+هشتم
+توانایی
+آیت‌الله
+مسیحیت
+تبلیغات
+محوطه‌های
+بارها
+ته
+سنچولی
+يک
+الف
+متصل
+ساسانی
+بویراحمد
+سروش
+نظرتان
+ربطی
+روایت
+بروز
+دیگه
+پژوهشی
+زبانی
+۱۳۷۸
+ثانیه
+برگزاری
+تبلیغ
+شاهنامه
+نزاکت
+قوی
+خواجه
+پوست
+پژوهش
+شروین
+سنی
+میباشد
+سرد
+بگویید
+شکایت
+بنی
+صدر
+مطلبی
+اسید
+کلید
+خسرو
+گذشت
+طلا
+شیرازی
+اي
+شناسایی
+تأثیر
+شیرین
+می‌کند،
+رأی
+فردوسی
+اگرچه
+چهارمین
+نمی‌کند
+زاپاس
+خشک
+جنگی
+برداری
+قادر
+بومی
+بنابر
+ديگر
+تقدیم
+حاشیه
+نگاره‌های
+۱۹۷۲
+اختصاص
+یونایتد
+بردن
+اندیشه
+حتماً
+بودجه
+داشت،
+افزوده
+۱۹۷۴
+بیرجند
+عضویت
+مستند
+بحثی
+الکترونیک
+امروزی
+بیرونی
+فتح
+معمول
+واژگان
+ادب
+نمی‌توان
+مرتضی
+اتصال
+مخالفان
+گویند
+ناقص
+سفارت
+۱۳۷۷
+المللی
+قسمتی
+چنان
+مدفن
+فضا
+گرچه
+ويکيپديا
+آمدن
+زیبایی
+نوشتم
+عهد
+رای‌گیری
+سرمایه
+نامعلوم
+ردیف
+تجارت
+نیک
+ایل
+یافتن
+اظهار
+گرد
+مایل
+اعراب
+قیمت
+چی
+مقدمه
+خرید
+عمق
+گمان
+هری
+معتقد
+داده‌است
+یوسف
+مردتنها
+بزرگ‌ترین
+فراوانی
+مرور
+جزء
+ناصر
+موشک
+رومانی
+دانست
+نادرست
+خود،
+فایل
+تلقی
+مشاهیر
+بوده‌اند
+آواز
+ضمنا
+بشود
+عثمانی
+مبنای
+قلب
+گوش
+جمعه
+آیت
+ویرایشات
+هاشمی
+دارند،
+استادان
+فرق
+همگی
+پرتغال
+ذهن
+پیر
+زیست‌شناسی
+پرنده
+بتواند
+ارمنستان
+اتریش
+اندکی
+آیین
+اتاق
+قطعه
+شناخت
+تغییری
+۱۹۶۸
+عبری
+معیار
+هفتاد
+روش‌های
+نکردن
+فاقد
+آیه
+دم
+عید
+مکانیک
+تک‌آهنگ
+نوبت
+دیوار
+گشتن
+درمانی
+مطمئن
+نصف‌النهار
+جنس
+تیره
+منظومه
+بایستی
+ریاضیات
+مهندس
+رییس
+بارگذار
+هواپیما
+میشه
+آرژانتین
+کلا
+کریم
+شاهد
+گر
+سنگی
+مسئول
+نشانه
+فیلمبرداری
+نوکیا
+جمشید
+تغییراتی
+کتب
+کرج
+استناد
+شریف
+ایرلند
+اف
+نسخهٔ
+چهره
+نوید
+کنگره
+منچستر
+رابرت
+نباشید
+پرویز
+مى
+نماز
+کمال
+گونه‌ای
+ژان
+دلیلی
+داری
+عالم
+اسب
+حمید
+قرارداد
+پیشینه
+قره
+خروجی
+کمونیست
+قاسمیان
+می‌گیرند
+شصت
+زمستان
+کلمبیا
+راهی
+محدوده
+نام‌ها
+میر
+لینوکس
+میلادی،
+بهداشت
+اگه
+سدهٔ
+۵۰۰
+بجای
+مغز
+پوستر
+حاوی
+لغت
+رسانی
+لوگو
+مسیح
+فرزاد
+فرمول
+مؤسسه
+مفصل
+پدید
+درام
+اردشیر
+آفریقای
+خرابکار
+تامین
+داره
+اتمی
+بزرگان
+محکوم
+نجات
+یادبودهای
+ریچارد
+رومی
+مدار
+تخریب
+بدانید
+درگیری
+بیستم
+افتاد
+محترم
+خودروها
+نوین
+مطابقت
+تاجیکستان
+نقش‌های
+افزار
+مراجع
+اتومبیل‌های
+عزیز،
+ضعیف
+امضاء
+بیگانه
+فرا
+اکثریت
+هرات
+می‌یابد
+پنجمین
+میکنند
+کنندگان
+فعلا
+۸۵
+نکات
+ارتباطات
+خواهید
+مجمع
+کنی
+یابد
+منطق
+دیدار
+دویست
+دوستانه
+آوری
+آلبوم‌های
+اتهام
+بینی
+مسیحی
+گری
+آنلاین
+ویژگی
+ادوارد
+امنیتی
+برایتان
+كرد
+دیگر،
+عام
+اصرار
+بودید
+تبلیغاتی
+حاجی
+هرچه
+۱۹۶۴
+انتقاد
+برسد
+شک
+توانید
+ویژگی‌های
+خوی
+۶۴
+زادگاه
+مساله
+فیزیکی
+هخامنشی
+غذایی
+نمی‌دانم
+سامسونگ
+گرفتند
+تاج
+موقع
+۱۹۶۹
+فاطمه
+سخنرانی
+سختی
+استدلال
+۱۳۷۶
+شهردار
+ار
+سلیمان
+متهم
+مذکور
+عملی
+چندی
+پدیای
+صادر
+منتظر
+ضرب
+تیم‌های
+تل
+حسینی
+گیر
+سراب
+تیرداد
+ویکی‌سازی
+تان
+مشروطه
+کوچکی
+مردمان
+ویکی‌پدیا،
+مجاز
+محاسبه
+بزنید
+جنگل
+مجموعه‌های
+واقعیت
+سان
+قومی
+صفحه‌ها
+قطب
+تالار
+خواب
+تاکید
+گاه‌شماری
+امین
+لذا
+آسیب
+هیات
+قد
+میلیارد
+کوچولو
+برقرار
+بالایی
+شیعیان
+قاضی
+برگرفته
+عنصر
+معانی
+ارتباطی
+شبکه‌های
+درود،
+۳۰۰
+مراحل
+لهستان
+معمولی
+نوار
+محس
+۸۹
+قبیل
+سیر
+دهیم
+شاخص
+عیسی
+ترور
+دمای
+تکامل
+کبیر
+درگیر
+سونی
+یاری
+۱۹۵۰
+آگاهی
+نیوز
+پیوست
+رچ
+خدای
+کودکی
+مرتب
+رژیم
+روبات
+ابتدایی
+میتوان
+هشتاد
+زادهٔ
+کشت
+بازسازی
+وسایل
+بتوان
+مجارستان
+پیاده
+میان‌ویکی
+فرمانده
+۸۷
+تهدید
+ویک
+محرم
+نهم
+احمدی‌نژاد
+۶۵
+خورد
+رسول
+تمیزکاری
+بندانگشتی
+گیاهی
+سیاست‌ها
+این‌که
+کلیه
+بهشت
+هندی
+مشکوک
+فکری
+عقیده
+اشغال
+نویس
+ستون
+خارجه
+۱۳۸۶،
+۸۶
+نمی‌گیرد
+کارخانه
+دانشجو
+پیوسته
+خاطرات
+پادشاهان
+۱۹۶۷
+غذا
+زرتشت
+سود
+خوشحال
+رساند
+آر
+فیلمی
+می‌پردازد
+تری
+لایه
+سپهرنوش
+ظاهرا
+مصدق
+کویت
+مال
+احداث
+کانون
+مد
+فرماندهی
+مرحوم
+مواجه
+۱۳۹۰،
+بايد
+افتاده
+دوم،
+گردیده
+کارل
+وگرنه
+ندارد،
+ترجمهٔ
+ساحل
+جم
+طرفی
+نگهدار
+شرط
+روان
+آبتین
+جوانبخت
+سازهای
+الکترونیکی
+پور
+نود
+جمعی
+راحتی
+حیوانات
+داروهای
+دستگیر
+بابک
+حداکثر
+دانش‌آموختگان
+حلقه
+راستای
+اراک
+نادر
+اثری
+زبانهای
+برندارید
+رشته‌های
+بستن
+برگردان
+آبشارها
+ریزی
+مراغه
+دروازه
+پذیرش
+نمایی
+مدیریتی
+منصفانه
+واژهٔ
+جانب
+متعددی
+رسد
+گوید
+شغل
+زاهدان
+نمای
+رواج
+واضح
+عده‌ای
+می‌مانند
+ایوان
+چوب
+نکند
+فلسفی
+معنا
+نمی‌تواند
+خورده
+سو
+باند
+ماهواره
+مرغ
+دشمن
+کوه‌های
+سرطان
+دبی
+پرداخته
+ایکس
+آشکار
+کاشان
+بغداد
+ببخشید
+ششمین
+منظورم
+جلب
+دیر
+مـهـران
+زند
+مناسبی
+خانگی
+تجزیه
+بالغ
+می‌داند
+علامه
+جولای
+برگ
+سیستم‌های
+سیستم‌عامل
+کاوه
+۷۵
+دراپر
+مدارس
+ظاهراً
+رنگی
+دهه‌ها
+چیست
+تظاهرات
+مربی
+سازمان‌های
+برپایه
+متشکرم
+دوازده
+ایراد
+گیتاشناسی
+می‌برد
+اسامی
+او،
+دارد؟
+بورکینافاسو
+تجهیزات
+شاهزاده
+دربار
+دانم
+زاویه
+قاره
+رهبران
+سرود
+ابهام
+۱۳۷۵
+ایمیل
+پیغام
+فرآیند
+دالبا
+پستی
+ظرفیت
+بشه
+سیتی
+هستیم
+پرتاب
+کمدی
+توی
+فجر
+این‌جا
+گرگان
+می‌دانم
+جواد
+شاتل
+خطاب
+الهی
+گرایش
+ملا
+دانشمند
+فیلتر
+نسبی
+شوم
+داستان‌های
+نمایشگاه
+تربت
+ممنونم
+آگوست
+پایدار
+مشارکت‌هایتان
+منطقه‌ای
+تنگ
+مقیاس
+شریک
+جزئی
+هویت
+بدهد
+نوشتهٔ
+بابا
+ادیان
+۱۹۶۵
+جورج
+هفتمین
+تصرف
+آهنگساز
+پاورقی
+دلیلتان
+حس
+کوچه
+رقابت
+نمایند
+رها
+مقامات
+منطقهٔ
+قلعه‌های
+فن
+مادرش
+متخصص
+تکنولوژی
+سالی
+کیفیتی
+زمین‌شناسی
+می‌دهم
+مک
+کشتار
+سنگین
+می‌نویسد
+نکردم
+ید
+پرو
+بدان
+باران
+دخالت
+درختان
+جوانی
+آنگاه
+حسب
+حرفه
+سندی
+چگونگی
+تبار
+توافق
+کتابهای
+اطلاق
+نامناسب
+مایکروسافت
+۱۹۶۶
+ارشاد
+فردوس
+صوتی
+روزگار
+نمودند
+سگ
+دارو
+خاورمیانه
+معلم
+گره
+ون
+سوخت
+مترو
+آموخت
+نشده‌است
+شماست
+هتل
+حدیث
+نداریم
+پیدایش
+۱۳۷۰
+میانی
+کنند،
+عقاید
+پیچیده
+قهوه
+فرشته
+نحوهٔ
+عجیب
+جداگانه
+هشتمین
+جزئیات
+همشهری
+مبنی
+کاتولیک
+اصفهانی
+حملات
+جاری
+پویان
+انگلیسی،
+برخلاف
+نيست
+اشخاص
+مجید
+سیمای
+کانی‌های
+تغذیه
+مربیگری
+برنامه‌نویسی
+‌پدیا
+فدراسیون
+اجرایی
+سیصد
+احمدآباد
+می‌خواهید
+جنگ‌های
+پیگیری
+حوادث
+اخیراً
+دیجیتال
+تکیه
+مریم
+الی
+۱۹۴۸
+كند
+عده
+اقدامات
+شعاع
+تخیلی
+ماه‌های
+۶۶
+آزمایشی
+شده‌است،
+واژه‌های
+دشتی
+موافقت
+قهرمانان
+جلال
+اچ‌دی
+الفبای
+نفس
+پایانی
+پانصد
+برایش
+ترجیح
+خواند
+سلول
+عصبی
+کوخرد
+آب‌انبار
+۶۲
+مفاهیم
+شنبه
+بالاخره
+دانسته
+هواپیمای
+نهمین
+ایالتی
+مو
+فارغ
+پلی
+دروغ
+اداری
+استقبال
+مسئولیت
+داده‌اند
+فدرال
+ترانه‌های
+نوازندگان
+چای
+دههٔ
+تراکم
+فهرست‌های
+مردی
+زمرہ
+گورستان‌های
+سوالات
+عباسی
+سردار
+محک
+ترکیبی
+رقم
+سعودی
+نرم‌افزارهای
+بازرگانی
+برلین
+نروژ
+مارتین
+فوت
+دیدنی
+کنفرانس
+فارسی،
+اهر
+نجف
+پذیرفته
+اینست
+ملکه
+سرخط
+كرده
+زنی
+قلمرو
+بخصوص
+امی
+بهائی
+نقاش
+کازرون
+تار
+گرفته،
+نظم
+۷۲
+خودداری
+شمس
+صفحه‌ای
+بیمار
+واقعه
+هادی
+۸۴
+خاتمی
+بارسلونا
+سرچشمه
+زنز
+برچسب‌های
+منتخب
+بحرین
+واشنگتن
+پاتر
+کرده‌ام
+شاهین
+زرین
+مارک
+توپ
+وقوع
+حدی
+آذری
+شاگردان
+معبد
+آرمان
+۱۹۶۲
+بیماری‌های
+بچه
+فعالان
+کوروش
+دارویی
+اوقات
+اوست
+می‌کنند،
+قضاوت
+ین
+دست‌اول
+فریدون
+تئوری
+نمی‌توانید
+دوستی
+حقیقی
+زندانی
+مقطع
+راستش
+۱۹۶۳
+شاپور
+۱۹۵۶
+آکادمی
+بازنویسی
+ارمنی
+۱۹۶۱
+مهران
+مردمی
+ندارید
+گذاشتن
+کوتاهی
+فقه
+تنکابن
+درجه‌بندی
+ژنرال
+مایع
+طرفداران
+مدارک
+بدلیل
+پیشنهادی
+باشند،
+ذرات
+دانشجویی
+نگارخانه
+نیت
+کیلوگرم
+سردشت
+ایده
+تسلیم
+برادران
+هزاران
+حادثه
+مرتضا
+خواستار
+نهضت
+نرسی
+آمیز
+استودیو
+قدمت
+مجموعهٔ
+مغناطیسی
+قطعات
+عمران
+توجهی
+فیلم‌ها
+كار
+۶۳
+رسم
+درب
+مبتنی
+امواج
+تمایل
+احزاب
+روحانی
+اردن
+۶۱
+عمارت
+می‌دانید
+گفتار
+دزفول
+داوری
+کا
+حقوقی
+زمستانی
+فولاد
+امریکا
+مزرعه
+بوده،
+رساله
+رامین
+جراحی
+محقق
+ابزارهای
+ویکی‌
+پزشک
+قبلاً
+ضلع
+سرور
+مجاهدین
+اخلاق
+گراف
+مانع
+مشارکت‌کنندگان
+قشلاق
+نوازنده
+پرده
+۱۹۵۳
+شیروان
+کاظم
+اریکسون
+طیف
+مسکو
+۱۹۳۰
+۶۸
+مقابله
+لوله
+علی‌آباد
+واقعاً
+معدنی
+طباطبایی
+شاهان
+تاريخ
+ودر
+ماهان
+یوشیمیتسو
+۱۹۴۵
+نمونه‌هایی
+البرز
+چهارمحال
+مالزی
+۱۹۵۸
+خودرویی
+بیاورید
+آبادی
+مخابرات
+می‌دهید
+رودبار
+جور
+یحیی
+كتاب
+وین
+می‌داد
+غلامرضا
+طایفه
+سطر
+خواهیم
+جانشین
+اقامت
+توده
+مشارکت‌های
+برود
+جویا
+می‌روند
+نتیجهٔ
+اختیاری
+اساتید
+آگاه
+ساوه
+قدس
+ناخالص
+چرخ
+پردازش
+خرم
+به‌
+کاربردهای
+فیلسوفان
+طب
+زمانه
+وحدت
+افغان
+منوچهر
+طرز
+بوسیله
+مدیری
+اخذ
+اصلاحات
+فرهاد
+۱۳۷۳
+بایرن
+تور
+۸۲
+بست
+راحت
+تقلید
+لهجه
+قرون
+افسانه
+۶۷
+منزل
+۰۰۰
+رکوردز
+تأثیرات
+افتتاح
+بزرگتر
+هندوستان
+نقره
+بهشتی
+پذیر
+عظیم
+سیم
+خواص
+اعتراضات
+سخنان
+رزیدنت
+مسجدهای
+هرگونه
+می‌آورد
+این‌ها
+دقیقاً
+بسکتبال
+صوت
+بوئین
+۱۲۰
+۱۵۰
+شور
+زودی
+توانند
+سربازان
+رویداد
+خب
+بنیان
+چلسی
+زیبای
+شورش
+خامنه‌ای
+برایم
+درخواستی
+روان‌شناسی
+جسم
+ممنوعیت
+اهورا
+چقدر
+ابوالحسن
+سالن
+صحت
+می‌خواهد
+۹۶۴
+نرخ
+اختلال
+رویدادهای
+خراب
+تونی
+دایره
+دبیر
+۸۱
+۱۳۶۸
+دانشگاه‌ها
+تقویت
+زلزله
+دهانه‌های
+کوهستانی
+محض
+۱۹۵۴
+نبودن
+بين
+کارکنان
+جملات
+خاکستری
+دادید
+فرایند
+دارا
+وفيات
+چهارصد
+خصوصیات
+چارلز
+گفتند
+ستاد
+۱۰۰۰
+پیتر
+انگلیسی‌زبان
+مجتمع
+وسعت
+می‌شدند
+۱۳۷۴
+نیروگاه
+گذار
+قوچان
+تحصیلی
+دهی
+میلان
+نمی‌کنم
+فرم
+پستانداران
+گردن
+۱۳۷۲
+۱۹۴۰
+جناح
+شوشتر
+پذیری
+لیبی
+اسلامی،
+بحث‌های
+سوء
+همسرش
+قفل
+اسکندر
+تحلیلی
+تحمل
+فعلاً
+۱۳۵۴
+میوه
+مصنوعی
+ارزیابی
+روزانه
+مدعی
+دانمارک
+فرستاده
+شناسه
+صبر
+شطرنج
+گفتید
+وسیع
+گام
+گوشت
+کرده،
+رصد
+کوهدشت
+اینطور
+نوجوانی
+ملت‌های
+محمدی
+۶۹
+لشکر
+بزرگراه
+۱۹۵۲
+پاینده
+۴۰۰
+جانبی
+ایول
+تجدید
+نیست؟
+حامد
+نشریات
+توماس
+مجازات
+قیام
+گپ
+سینا
+۷۸
+بس
+وظایف
+کوهستان
+اینجاست
+میدهد
+کارها
+سالها
+یادبود
+آبادان
+طبس
+خوردن
+روزه
+مسکونی
+اعظم
+دموکرات
+خشونت
+۸۳
+هوشنگ
+تخصص
+سیما
+منظر
+علمیه
+سالم
+پیکسل
+کمکی
+خواسته
+ایرج
+مدنی
+گفتن
+آذربایجانی
+ره
+اتمام
+آلاباما
+۱۹۲۰
+ابی
+بام
+فقیه
+کیلومترمربع
+عوارض
+۱۳۵۰
+ترس
+بازگردانی
+سعدی
+موثر
+کلیبر
+انقلابی
+وبسایت
+روانی
+موردی
+دختران
+روس
+بم
+پاک‌کن
+داشته‌اند
+یوتی‌سی
+صدها
+پانویس‌ها
+نفتی
+ورزقان
+کمبود
+نابود
+فرانک
+دان
+۷۶
+جرج
+جدایی
+کیهان
+نامش
+تبریزی
+کتیبه
+حکومتی
+قسمت‌های
+صرفا
+۷۱
+اندازی
+قدم
+منحصر
+عموم
+پهنای
+پدیده
+روغن
+رسانه‌های
+اطلاعات،
+سایت‌ها
+اکران
+سلامت
+بالاترین
+پیروی
+۱۹۵۱
+مصداق
+۷۳
+شکار
+مباحث
+پوویا
+فاصلهٔ
+فاز
+۷۷
+حالیکه
+شهریار
+۱۹۵۷
+درخشان
+آن‌جا
+تنهایی
+نکرد
+عدالت
+می‌نماید
+مقبره
+سانسور
+داده‌ها
+شاهرود
+تخمین
+نشست‌های
+۱۹۳۶
+جین
+روبرو
+پس‌زمینه
+نیرو
+اخلاقی
+داستانی
+سینه
+شاهنشاهی
+مولانا
+گاو
+استخوان
+گرگ
+دکتری
+اند،
+کشف‌های
+سنندج
+۷۴
+ساحلی
+برهان
+پیش‌نمایش
+کردم،
+دوره‌های
+۱۳۵۶
+آغازین
+سالانه
+بستگی
+تخم
+۹۹
+سیگنال
+ویکی‌پروژهٔ
+ناقض
+خودمان
+کرد؟
+ویرایشگران
+داوران
+برداشته
+۱۳۷۱
+یکمین
+ریزشگاه
+سوار
+سلاح
+شایسته
+سفیدپر
+غزه
+ترکیبات
+لاله
+اولی
+گذر
+جک
+ذیل
+دراز
+۹۵
+پان
+درصورت
+ایرانشهر
+عرصه
+پیروان
+پردازنده
+زایش
+مدینه
+انفجار
+کمپانی
+فرشتهٔ
+واحدهای
+حرارت
+بعداً
+۱۹۴۹
+همینطور
+استخراج
+ملاقات
+فرو
+پارامتر
+منتقدان
+آزمایشگاه
+نوشته‌شده
+اصطلاحات
+بتوانند
+مشتری
+متوقف
+اجباری
+مسلح
+سلجوقیان
+کندی
+اسکاتلند
+فیلسوف
+می‌سازد
+زود
+۷۹
+رجبی
+هفتصد
+تقی
+معدن
+مار
+فراز
+ایالت‌های
+ایمان
+ابراز
+ممسنی
+رادیویی
+سرکوب
+پیوندها
+۱۹۵۹
+توزیع‌کننده
+کشید
+بال
+۱۳۵۸
+۱۹۵۵
+شفاف
+کلام
+یکبار
+رصدخانه
+موسوم
+صلاح
+اخیرتان
+کالج
+واز
+شیکاگو
+جنبه
+۱۳۶۹
+عاشق
+کک
+خنثی
+امیرکبیر
+آنقدر
+زبان‌شناسی
+مشاور
+نمایشگر
+دا
+مِنْ
+آرزوی
+آئین
+می‌آیند
+شکلی
+۱۳۶۰
+سقف
+فرامرز
+بحث‌ها
+همت
+خیام
+تصادفی
+میتواند
+تجاوز
+روح‌الله
+روستاها
+هواپیمایی
+گلدن
+منظورتان
+کرمانی
+قله
+ضربه
+ساکنان
+اورشلیم
+مجدد،
+ویکی‌پ
+معتقدند
+۱۹۳۸
+محیطی
+جعفری
+خطا
+ویروس
+نگار
+سال‌ف
+ابراهیمی
+هشتصد
+نکنم
+ذوب
+رایت
+هاست
+متنی
+نان
+اضافی
+باله
+اصغر
+تایلند
+را،
+پیانو
+سکونت
+تالیف
+اختصاصی
+بهتری
+ترابری
+چو
+دیو
+زندگی‌نامه
+شیشه
+قلبی
+تحریک
+کیش
+ستاره‌ای
+اختراع
+برآورد
+سزار
+دهستانی
+مجسمه
+برطرف
+سپرده
+پارلمان
+رمز
+درسی
+سپاهان
+منصوب
+۱۹۴۱
+پروانه
+جمع‌بندی
+فعل
+کربن
+دژ
+تفکیک
+قفقاز
+همراهی
+عبدالحسین
+بسيار
+مواليد
+۲۵۰
+پیرو
+معاونت
+پیرانشهر
+۹۱
+معنوی
+کاروانسرای
+دفن
+سیزدهم
+ند
+اینقدر
+هخامنشیان
+دستگیری
+گل‌های
+می‌خواهم
+گیرند
+متفاوتی
+شیلی
+مراکش
+کنسرت
+بدهم
+تومان
+کهکشان
+اوضاع
+اندونزی
+چنانچه
+جایزهٔ
+بدهند
+کروبی
+سکه
+گرفته‌اند
+می‌شوم
+تضاد
+ملایر
+شیطان
+سهم
+اخطار
+حرم
+موافق،
+هیتلر
+واسطه
+ناظر
+نمودار
+بگوید
+تیمور
+قصر
+مکانی
+فرودگاه‌های
+۱۹۴۶
+جهاد
+مقداری
+داد،
+اندک
+دکترای
+فیلیپ
+۱۹۳۳
+کارگران
+آماری
+۹۸
+تست
+هستی
+میزبان
+تقاضای
+اوبلاست
+شیوه‌نامهٔ
+من،
+محتوا
+مربیان
+دیسک
+معتبری
+زدایی
+صعود
+حکمت
+مخفی
+زمینهٔ
+دهان
+گو
+رمضان
+ششصد
+هم‌اکنون
+شکسته
+‌است
+حرفی
+۹۶
+هواداران
+تبعید
+نشین
+توجیه
+مکه
+جاذبه‌های
+منافع
+بیفزایید،
+عرفان
+کشی
+آمریکایی‌های
+عقل
+وفات
+سیب
+پربارتر
+کنه
+تألیف
+بنیانگذار
+دموکراسی
+نهصد
+یادم
+سراسری
+تفکر
+لارستان
+برگزیدگی
+رباط
+لس
+حساس
+حبیب
+ویکی‌پدی
+فرود
+همکاران
+تشویق
+تحویل
+باقری
+داده‌های
+معرض
+گلوب
+کلیسا
+ویکی‌پد
+کف
+۱۳۶۷
+امضای
+بخواهیم
+خالد
+فلزی
+نظرخواهی‌ها
+آیات
+درگذشته
+شباهت
+هم‌چنین
+تعلق
+بگیرند
+گوناگونی
+نایب
+حساسیت
+کارگردانان
+مغول
+سازمانی
+دیا
+داغ
+خواهی
+فشرده
+ماجرای
+زندانیان
+تصاویری
+بیماران
+کهنه
+مکمل
+بخواهید
+رایگان
+رویه
+ماری
+فرمایید
+بلورین
+فورد
+درخواست‌های
+سازد
+پروتکل
+راس
+فرقه
+وفق
+نازی
+احتمالی
+طلب
+اقماری
+محدودیت
+همایون
+۱۱۰
+هیأت
+احسان
+ابرخس
+بخواهد
+له
+مهرداد
+می‌شوند،
+سکوت
+مهاجر
+صدور
+بازیگری
+آسان
+سراغ
+اولا
+محلول
+وان
+کوی
+الکساندر
+لیسانس
+خزر
+۹۲
+شکنجه
+امیررضا
+گرجستان
+بازرسی
+عکاس
+۱۳۶۲
+آسیاب
+گویی
+شود؟
+حیاط
+موجهی
+ارکستر
+ارباب
+نویسندهٔ
+یخ
+السلام
+نسب
+بوی
+۱۹۴۷
+نمي
+اعضا
+خانوادهٔ
+ویکیپدیای
+سحابی
+شاهی
+شیوهٔ
+زیارت
+تحقیقاتی
+فعالیتهای
+کاغذ
+تهرانی
+پروفسور
+بریتانیایی
+اخیرا
+ایرنا
+مادرید
+۱۳۵۵
+زمینه‌های
+ببینم
+۱۹۳۴
+می‌بینید،
+فیفا
+صالح
+متداول
+ربط
+سطوح
+ی‌پدیا
+خواهدشد
+بحران
+۱۹۳۹
+افکار
+پیراهن
+۱۹۳۲
+انتظامی
+بلافاصله
+ارایه
+کمیسیون
+راز
+محمدحسین
+آبیلا
+محبوب
+سایه
+جوامع
+داور
+۱۹۰۰
+زودتر
+ولز
+سوخته
+تأیید
+ابوالقاسم
+برادرش
+بمب
+امتحان
+آرتور
+فرستاد
+صص
+دانشجوی
+کارگر
+هوش
+اتفاقا
+غلامحسین
+قربانی
+می‌خورد
+احکام
+سرزمین‌های
+ضمناً
+فینال
+قبرستان
+ضعف
+نامهای
+گندم
+قواعد
+تند
+تایپ
+ماموریت
+موسیقی‌دانان
+گوشه
+دری
+مناسبت
+ارقام
+چاراویماق
+مبانی
+گذاشته‌اید
+ابر
+مدخل
+یو
+شناس
+اندازهٔ
+غالب
+قنات
+مبتلا
+ویکی‌فا
+نوزدهم
+مونیخ
+کابینه
+میرحسین
+باقر
+۱۹۳۵
+سامان
+هلندی
+موجودات
+فنلاند
+برعهده
+مدافع
+قطار
+تغییرات،
+فرمانروایی
+واگذار
+حکیم
+آهنگسازان
+شوند،
+تحول
+مرکب
+مقادیر
+اختیارات
+نوشتاری
+چندانی
+جان،
+هکتار
+رازی
+محله‌های
+آوردند
+صف
+مقاله،
+تدریج
+نیستید
+تسلط
+اسلام‌آباد
+آزمون
+ویرایشاتشان
+اصولا
+صفت
+۱۹۳۷
+می‌شد،
+سفیر
+تمرکز
+شهروند
+نمودن
+ویتنام
+نمایندگی
+گردش
+سران
+فر
+ایمنی
+خو
+مشارکت،
+پسرش
+می‌ماند
+متروی
+ختم
+علمای
+۱۳۶۴
+ران
+کودتای
+قهوه‌ای
+دایرة‌المعارف
+لنگه
+درونی
+سرا
+خاموش
+منصب
+ماد
+دومی
+کشور،
+سوادکوه
+خدایان
+بی‌طرف
+ماجرا
+دماوند
+بردسکن
+ویکی‌نویس
+ماهنامه
+یادگیری
+قابل‌
+هاشم
+همگان
+روانشناسی
+محمدآباد
+نگهبان
+آفرید
+گیرنده
+۱۳۵۲
+۱۳۸۹،
+ترکان
+هوی
+دندان
+خوش‌آمد
+گرفتم
+پایهٔ
+دانلود
+جفت
+فهم
+گوشزد
+متشکل
+رسمیت
+مقدماتی
+جویباری
+پيش
+کنیم،
+استانداردهای
+سرجعبه
+آنجایی
+خیریه
+بیش‌تر
+في
+دکمه
+ماندگار
+فیروزآباد
+بخار
+فیلیپین
+جلگه
+آرامش
+۹۳
+رونق
+پاسداران
+میتوانید
+کاووس
+۱۳۵۳
+۶۰۰
+مرو
+نیافتید،
+نداره
+نجفی
+الهام
+میکنید
+ناصرالدین
+قصه
+آمدند
+پراکنده
+خواهان
+روي
+مرودشت
+مسیحیان
+عبدالهی
+حسابی
+پاییز
+جانبدارانه
+کی‌پدیا
+حین
+پلی‌استیشن
+اعصاب
+می‌توانیم
+فرح
+نمک
+به‌طور
+۹۷
+۱۳۵۹
+گرافیک
+زمین‌لرزه‌های
+منتهی
+مستقر
+تقدیر
+۱۹۳۱
+می‌رفت
+افسانه‌ای
+برخط‌اند
+آبشارهای
+برخوردی
+عکسی
+خاور
+مورخ
+جمال
+باتجربه‌ترند
+به‌کار
+مطالبتان
+راه‌آهن
+نفع
+پاجعبه
+نسخه‌های
+بدی
+آکادمیک
+امتداد
+یوشیچی
+رضاشاه
+تأمین
+خواهشمندیم
+لو
+رئال
+خراسانی
+سردر
+آشپزی
+ایرانیکا
+شاگرد
+سرای
+یزدی
+نامزدهای
+وکیل
+نقشهٔ
+اکسیژن
+شفافیت
+یکی‌پدیا
+مقیم
+ویل
+یادآوری
+بلوری
+شعاعی
+قائم
+آلن
+استانبول
+بکنید
+عمیق
+تایمز
+سلماس
+بی‌طرفی
+بیل
+بویژه
+تک‌آهنگ‌های
+می‌باشد،
+جماهیر
+وحشی
+نمایشنامه
+روایات
+غنی
+کسروی
+بازتاب
+شاملو
+اروپای
+برنج
+بيشتر
+اخراج
+جمعیتی
+اخترسنجی
+شوش
+خوشنویسی
+تقاضا
+مکان‌های
+کریمی
+۱۹۲۹
+دفاعی
+برگشت
+کنید؟
+معمار
+خوش‌حال
+قوه
+۱۳۶۵
+اکسید
+لاهیجان
+آئیله
+عقاب
+پائین
+سوالی
+کنم،
+مان
+خواف
+انجیل
+محاکمه
+ور
+كنيد
+میخی
+مرزهای
+روشی
+بل
+آداب
+زرتشتی
+باشی
+جهرم
+آور
+شهادت
+رسیده‌است
+سادات
+زحمات
+بنویسم
+شریعتی
+بان
+مرتبه
+آثاری
+شه
+کابلی
+تویوهارا
+بیجار
+می‌زند
+نگران
+کر
+سیرجان
+اماکن
+ایلخانی
+ماست
+گزینه
+دوشنبه
+شواهد
+قاعده
+موازی
+شتاب
+۱۳۶۶
+حال،
+ویا
+می‌برند
+۱۹۲۴
+نت
+نجومی
+تعارض
+سادگی
+۱۳۰
+خلافت
+تأثیرپذیرفته
+طبری
+تعقیب
+کاشانی
+منع
+توضیحی
+دورود
+حبس
+بهایی
+محاسبات
+بگوییم
+تنوع
+معادله
+۱۳۵۱
+کوچکتر
+جوی
+دورنما
+شرایطی
+فرماندار
+هریوا
+پی‌گیری
+۱۹۲۸
+می‌نامند
+فومن
+الجزایر
+سیاست‌مداران
+۹۴
+مقدم
+طرفین
+چمن
+صفویه
+یر
+نابودی
+رفسنجانی
+معادن
+۱۳۴۷
+نیل
+سانتی
+دام
+نامه‌ای
+ات
+یافته‌است
+می‌دارد
+بقعه
+۸۰۰
+پرتو
+قید
+ظرف
+لری
+قدیمی‌ترین
+انسان‌ها
+برنامه‌ریزی
+وسطی
+مسلم
+چالوس
+پیشتر
+پوشیده
+فرزان
+میشوند
+منظم
+تلفن‌های
+خوشحالم
+تجمع
+رنج
+آباد،
+مختصر
+هماهنگ
+روشهای
+لفظ
+چوبی
+همين
+شادی
+وسیعی
+گور
+کردیم
+تندیس
+مواقع
+الیگودرز
+نسبتاً
+هٔ
+مخصوصا
+شی
+مشهورترین
+می‌خواستم
+انها
+نهنگ
+حرکات
+دنباله
+قانع
+۱۹۴۲
+داوود
+می‌کردم
+جاوا
+تعادل
+پزشکان
+نحوی
+مادی
+ردهٔ
+گذاشتم
+۱۳۶۳
+کمان
+بعدا
+شرمنده
+ویراستار
+ایام
+اسلواکی
+ناراحت
+متحرک
+تجربی
+خاصیت
+گیلانغرب
+کشتن
+مرزی
+پرچم‌ها
+ذهنی
+لر
+مساوی
+رستمی
+کرم
+ازبکستان
+رضایی
+احیا
+هنگ
+توانم
+شکر
+مند
+کمتری
+بردارید
+قبر
+فرعی
+ایم
+معارف
+پیوندی
+اطلاع‌رسانی
+بسازید
+کردند،
+کلیدی
+سيستم
+لغو
+بسیج
+سرنوشت
+شاخه‌های
+طرفدار
+سیاوش
+کشیدن
+پناه
+هشترود
+ورزشگاه‌های
+صفحه،
+عارف
+ابرکوه
+،خرد
+دراین
+بایر
+قلی
+دشوار
+بیزانس
+بهانه
+جالبی
+قبیله
+بیژن
+چنانکه
+می‌
+بیانیه
+آلفا
+کارگاه
+استوار
+کش
+پویا
+چیزهایی
+نمی‌کنند
+رهنمود
+وصل
+کریس
+پسوند
+مهاجم
+جامعه‌شناسی
+مجددا
+ایر
+احتیاج
+متأسفانه
+خودکشی
+۱۳۴۸
+مراتب
+یازدهم
+خام
+نوجوانان
+بدانم
+طنز
+چهره‌های
+شبانه
+دامغان
+مقصد
+وزیران
+لوح
+شهرام
+بده
+جلا
+دشتستان
+روزنامهٔ
+چهارشنبه
+دالاهو
+ضریب
+تکنیک
+سرخس
+ولي
+دکترا
+آنجلس
+خرس
+مجتبی
+نهاوند
+مسیه
+حسینیه
+كنند
+ملاک
+۳۶۰
+هندسه
+ابو
+کامپیوتری
+۱۳۴۵
+۱۰۱
+صندوق
+بلی
+آقایی
+قالی
+۱۹۲۵
+اشتغال
+اوستا
+خاش
+باتری
+قربان
+رمان‌های
+زير
+خالص
+زدم
+باشد؟
+توقف
+دوستانی
+اجتماع
+کوهی
+کلاه
+قائل
+فلز
+مطلوب
+گربه
+نگرانی
+زوج
+یار
+سرپل
+نوروزی
+۱۹۲۶
+الآن
+اختلالات
+بریتانیکا
+ايجاد
+آزار
+سا
+پروتئین
+بادی
+مجزا
+سانتیمتر
+اله
+پسران
+۱۳۴۶
+دروس
+کور
+مطلع
+نستعلیق
+خطرناک
+لوگوی
+دنده
+ویژه‌ای
+بهینه
+الکترون
+سقز
+عددی
+کاش
+جیرفت
+راسته
+بتوانم
+نسبتا
+یازده
+کمیل
+مانفی
+انتخابی
+نداشتن
+حرکتی
+کمترین
+مرورگر
+مقاله‌ی
+برنز
+انشای
+فراتر
+وسیلهٔ
+انزلی
+سوم،
+آشور
+اجزای
+روزنامه‌های
+نداشتند
+برتری
+توقیف
+گنجایش
+نویسندگی
+واشینگتن
+وَ
+عبد
+ماهیت
+ترکمن
+تابش
+برف
+اثرات
+نمایشی
+است‌
+حدس
+بین‌الملل
+۱۹۲۳
+راوی
+بامداد
+تنگه
+گذراند
+اتفاقی
+هالیوود
+گشته
+اسمیت
+باش
+آلی
+ترکمنستان
+سوسیالیستی
+مجلات
+۱۹۱۸
+بدنه
+قاهره
+خانهٔ
+بید
+ایرانی،
+۱۳۴۰
+پری
+اشتباهی
+نهاده
+وب‌سایت
+شهروندان
+همایش
+خوان
+نژادی
+عملیاتی
+افزود
+مخلوط
+رودسر
+الیزابت
+نمونه‌ای
+مغزی
+قضایی
+یان
+گالری
+بگو
+ملقب
+ایفا
+انیمیشن
+بخش‌هایی
+شکستگی
+سوپر
+کانی‌شناسی
+ویتامین
+می‌دادند
+پرجمعیت
+درسال
+۱۰۵
+ستاره‌های
+مدیا
+بندپی
+تردید
+كشور
+ماهیان
+پوزش
+انگار
+اسلام،
+ايشان
+سرپرستی
+تاکستان
+۱۹۲۷
+۱،
+پذیرفت
+نما
+مشتق
+باستان‌شناسی
+امامی
+اتم
+ندیدم
+نوشهر
+گزیدن
+۱۹۱۹
+حیوان
+بنظر
+کورش
+اواسط
+رفتند
+تبادل
+میلی
+استون
+دانستن
+آمریکا،
+حصار
+آینه
+گرایی
+قبایل
+کبیسه
+۱۹۴۳
+۱۹۱۲
+۱۹۱۷
+برقراری
+فيلم
+نداشتم
+سرده
+فعالیت‌ها
+بوستان
+خیال
+کارش
+کربلا
+کنم؟
+سیاست‌مدار
+معنایی
+آلودگی
+شماری
+کودتا
+پانزده
+المعارف
+کالبدشناسی
+عظیمی
+علائم
+کنسول
+نحو
+سوئدی
+گرفت،
+مازندرانی
+مثال،
+منسوب
+نشدم
+ویران
+درخشندگی
+بندرعباس
+ارگ
+سامانه‌های
+بیمه
+انجامید
+اردکان
+متمرکز
+سلولی
+مرسوم
+صادقی
+هيچ
+امثال
+ولتاژ
+مقررات
+رکورد
+بلخ
+نامزدی
+پردیس
+راه‌های
+‌ای
+مانده‌است
+هدیه
+خاکی
+کلاً
+كنم
+جویبار
+گرجی
+سنجش
+بو
+مثلث
+جمهوری‌های
+خاتمه
+رشتهٔ
+بوش
+حسین‌آباد
+۱۳۴۹
+جنگلی
+عزل
+مزار
+اختلافات
+زاکسن
+عشایر
+دشمنان
+کنگ
+یهودیت
+الگویی
+فرکانس
+تحریف
+پژوهش‌های
+شام
+لار
+می‌بینید
+مریخ
+علی‌اکبر
+عامه
+روزها
+زخمی
+عبارت‌اند
+ویکی‌های
+بری
+کارائیب
+رده‌فرد
+رحیم
+نگاشته
+القاب
+قاتل
+مکرر
+محمد،
+ابداع
+ویدئو
+اسطوره
+جامد
+ژنتیک
+مجاور
+سیاسی،
+رفسنجان
+بعید
+مرند
+روحانیون
+اریک
+قریب
+نثر
+تحریم
+موزیک
+برداشتن
+ارتفاعات
+اشکالی
+غذاهای
+شهاب
+بورس
+سال،
+نقشه‌های
+عروس
+نخل
+محلات
+آلبرت
+فا
+دشمنی
+۱۹۴۴
+يكي
+جایگزینی
+تفاصیل
+خدابنده
+اقلیت
+مشخصی
+محاصره
+زین
+افتخارات
+این،
+بي
+سواحل
+اندام
+فرماندهان
+دانند
+دوازدهم
+بجز
+آرا
+بهائیت
+۱۹۲۱
+کالا
+استقرار
+تلخ
+تکه
+جلوه
+امان
+نگونبانگونی
+فیلمنامه
+مترجمان
+کتاب،
+بستر
+تولیدی
+باغ‌های
+نباشند
+انصاری
+محمدتقی
+ان‌جی‌سی
+سلمان
+پهن
+گستره
+سودان
+پرهیز
+همون
+موسسات
+جاهای
+اشرف
+سواد
+مصوب
+دانه
+اينكه
+شعبه
+تشیع
+اپرا
+مجری
+موضع
+۱۴۰
+گلوله
+دارایی
+آوردم
+۱۸۰
+بلد
+سیروس
+گرمسار
+مهارت
+پیشاپیش
+ساختمانی
+باختر
+نامید
+ایفای
+باریک
+تعجب
+عقد
+فرمودید
+وطن
+گوی
+قبرس
+محبوبیت
+کوچ
+جدید،
+اخترشناسی
+کلمهٔ
+ایذه
+احوال
+پراکندگی
+ویرایش‌ها
+سانتا
+نپال
+چرخش
+فخرالدین
+دستگاه‌های
+پاراگراف
+می‌توانم
+پیکر
+بعد،
+جای‌ها
+یاران
+بیگ
+پنجره
+رامسر
+خواه
+انکار
+می‌کشد
+۱۹۲۲
+برعکس
+پاره
+اکشن
+لغات
+گردآوری
+سهراب
+نیز،
+عراقی
+پاسارگاد
+نوجوان
+مخفف
+هیچگاه
+کاندید
+بهروز
+بناب
+تهمت
+آفریقایی
+جسد
+پژوهشگران
+موسس
+بلاگ
+آبخواره
+مایه
+مجدداً
+لقب‌ها
+تلسکوپ
+استانی
+منتقد
+داراب
+دلخواه
+فرش
+بارگذاری‌شده
+صحرای
+نوک
+فارسي
+رسانه‌ها
+ماکو
+۱۳۶۱
+استفادهٔ
+دستیابی
+سرو
+بردار
+آلبوم‌ها
+مکعب
+تب
+می‌گرفت
+وی،
+قطعی
+اقبال
+پلاک
+برابری
+جوش
+التحصیل
+بردند
+شارل
+خشم
+سارا
+گناه
+حوصله
+بیافزایید
+اصیل
+خودمختار
+نمی‌دهد
+داند
+سراوان
+صور
+یعقوب
+شنیدن
+اشتراک
+دفع
+اد
+ه‍
+وستفالن
+بهائیان
+پناهگاه
+مسیرهای
+هست،
+مذاهب
+گران
+تابعیت
+یابی
+ولسوالی‌های
+اسرائیلی
+تاریکی
+تعطیل
+همکار
+زور
+خلیل
+شوخی
+سلول‌های
+تنش
+کرسی
+نصف
+می‌افتد
+بیات
+فضل
+نامشخص
+تعبیر
+۷۰۰
+شو
+سوسیالیسم
+اب
+پرچمک
+دموکراتیک
+تحولات
+بگیریم
+گسترده‌ای
+آریایی
+کیلو
+والی
+براون
+ناچار
+گنج
+بلندترین
+انگشت
+محتواهای
+۱۳۸۵،
+نه؟
+یهود
+وضوح
+بلوک
+بلور
+باکیفیت
+غير
+بدل
+نادیده
+لاریجان
+دلفین
+جاز
+حاکمان
+دوری
+آرای
+خاوری
+شناختی
+ماریا
+شیب
+نیوزیلند
+مشکین
+منتظری
+خریداری
+۱۱۵
+جانی
+به‌شمار
+تعلیم
+تأکید
+اندازه‌گیری
+یافتند
+مادری
+فون
+بادن
+کدهای
+بدنی
+لوئیس
+ادامهٔ
+مبلغ
+صلیب
+می‌بایست
+آریا
+۱۲۵
+بفرمائید
+قراردادی
+شر
+گفت‌وگو
+گرینویچ
+مولکولی
+نیو
+سايت
+۱۹۱۴
+جزیره‌های
+رسیدند
+فرمت
+قائم‌شهر
+تفرش
+نظریهٔ
+خواستید
+هافبک
+دائمی
+تنیس
+می‌دهد،
+ماتریس
+باخت
+سیا
+مغرب
+سل
+اسلحه
+ذهاب
+دهد،
+فرقی
+صرفاً
+وبلاگ‌ها
+نمیشود
+راضی
+آتن
+چراغ
+حالتی
+شلیک
+الیور
+اینکار
+برپا
+آهنگرکلا
+لویی
+نیما
+بجنورد
+نهادهای
+محروم
+نکا
+لب
+وحش
+اعتراضی
+ژن
+ويكي
+عثمان
+نیشابوری
+بلک
+کنندهٔ
+موتورهای
+رئیس‌جمهور
+حکایت
+حاکمیت
+نفره
+هرسین
+مالیات
+انجام‌دادنی‌ها
+خودت
+مناقشه
+کارهایی
+غذای
+نوردراین
+علل
+دیپلم
+دادگستری
+پیچ
+لیورپول
+سرپرست
+گلی
+تفت
+جنسیت
+امری
+صبا
+اسفراین
+ریخته
+برا
+ناپلئون
+دبستان
+ویدئویی
+خمیر
+انتخاباتی
+گفته‌است
+ورزشکاران
+عادت
+آرایه
+اعتراف
+استخدام
+آرامگاه‌های
+دوتایی
+ارنست
+عمدتا
+مجهز
+زدند
+۱۳۳۰
+۱۳۸
+۱۳۳۲
+آلبانی
+نشانه‌های
+باغین
+شعبان
+فارسی‌زبان
+نیمی
+سازگار
+زبانان
+پیست
+کارایی
+گرافیکی
+کوره
+اتیوپی
+ساوجبلاغ
+مشرق
+فِي
+سیزده
+۱۰۳
+مردم‌شناسی
+بلندی
+محمودآباد
+بتا
+۱۰۲
+مراد
+افتخاری
+سهام
+امیدان
+دلایلی
+غول
+۲،
+مازیار
+عمدتاً
+مملکت
+۱۳۴۲
+انگیزه
+فرنگی
+مینودشت
+بقایای
+ابوالفضل
+فاکس
+میگوید
+همچنين
+شعری
+لس‌آنجلس
+تائید
+تاریک
+تونس
+بستان‌آباد
+کارمندان
+اسحاق
+۱۶۰
+کارگری
+پتانسیل
+سحر
+۱۰۹
+نیازهای
+آرسنال
+افزون
+نظریات
+کوبا
+فهرستی
+آزادگان
+کارشناسان
+تزریق
+کاپیتان
+حدودی
+فیل
+والیبال
+ازای
+این‌گونه
+همانگونه
+نداده
+سردبیر
+تالش
+سام
+می‌گذرد
+آنتی
+مجلهٔ
+بازی‌ها
+رجال
+هم‌درازا
+دختری
+رفته‌است
+ابریشم
+فلوریدا
+بلغارستان
+مصری
+بلوار
+دليل
+راه‌اندازی
+۱۰۴
+شمشیر
+ندا
+صادرات
+دانیل
+هریس
+کله
+حوزهٔ
+نشسته
+بیاندازید
+۱۲۸
+وبه
+تازگی
+شورا
+سروده
+درمورد
+شدند،
+قطعا
+اراضی
+می‌گویید
+حامی
+خوراکی
+جایزه‌ها
+کویر
+مفهومی
+رودهای
+زمان،
+کمیاب
+مخاطب
+سوابق
+سلامتی
+علوی
+خواندم
+نهایتا
+هوشمند
+همیشگی
+همدیگر
+سازه
+ترویج
+مقر
+قشم
+تغيير
+دیروز
+مخالفم
+نجوم
+آرزو
+عموماً
+افقی
+گوشی‌های
+رباتیک
+کلاته
+لورنس
+وزیری
+پرداختند
+رجب
+جوزف
+سپری
+تایوان
+مقاله‌هایی
+بود؟
+بزند
+مرسی
+باختری
+صلاحیت
+نمی‌آید
+بهشهر
+جماعت
+خونی
+نوشته‌است
+ازنا
+مکانیکی
+فضاهای
+فرمانروایان
+رزمی
+همسایه
+همدانی
+۱۹۰۸
+۱۹۰۵
+هردو
+۱۱۴
+هرم
+شهرکرد
+۱۰۷
+آب‌های
+متقاعد
+شویم
+نبود،
+نویسان
+هم‌زمان
+شهر،
+صخره‌ای
+ارزشمند
+۱۳۲۰
+حذفش
+سامی
+ثانویه
+دن
+احساسات
+بوئینگ
+نام،
+شبکهٔ
+شمرده
+طوایف
+باری
+جبر
+اجازهٔ
+بزرگ،
+بهم
+۱۱۱
+جهان،
+مولوی
+تفریحی
+ماساچوست
+آنها،
+اجتماعی،
+طاق
+خوشامدید
+نیامده
+اچ
+ملاحظه
+کمبریج
+زی
+برش
+می‌گذارد
+شدگان
+بدو
+درحال
+چارچوب
+شده‌اند،
+قطبی
+لئون
+هیدروژن
+کاردانی
+درمیان
+نقاشان
+شنیده
+چنين
+آتشکده
+کوههای
+قروه
+هجوم
+سرهنگ
+عکس‌های
+تاجگذاری
+خرج
+۱۳۴۴
+جعلی
+آمیزش
+راهپیمایی
+سرشار
+فیروز
+دوک
+بهداشتی
+شکی
+ماهواره‌ای
+طاهره
+زیرصفحه
+تسخیر
+مخزن
+حیدر
+اتفاقات
+غزل
+زهج
+بولیوی
+کردها
+۱۹۰۱
+قند
+نخست‌وزیر
+بازهم
+عصب
+مهاباد
+پرس
+گازی
+ابزاری
+مبدل
+۱۳۵
+میشل
+مستقیما
+صدام
+محکم
+فلزات
+طنابداران
+پروژهٔ
+امّا
+صحرا
+۱۰۸
+جملهٔ
+شوهر
+هواپیماهای
+سعادت
+جعل
+صفحه‌کلید
+اوباما
+۱۹۰۶
+انب
+اپل
+مرخصی
+معیارها
+دانید
+دعا
+تلفات
+تضمین
+آرامی
+دائم
+شد؛
+چرخه
+شجره‌نامه
+آفرینش
+معادلات
+رسما
+مزبور
+بارش
+برکه
+نبی
+مصالح
+والتر
+سدیم
+بحثش
+پیشگیری
+پروین
+نشود،
+می‌گردند
+مسافر
+راین
+بتن
+خوشه
+طوسی
+جونز
+وابستگی
+اسیر
+خیابانی
+بت
+اینجانب
+ببینیم
+لیکن
+بگذاریم
+شراب
+انگیز
+برروی
+حاجی‌آباد
+پارسک
+اعزام
+اعطا
+فقر
+علي
+کارنامه
+حجاب
+اینک
+جمع‌آوری
+درهم
+خواهشمندم
+اینه
+گانه
+پارچه
+گردیده‌است
+مداوم
+آلوده
+حقایق
+جعبه‌دندهٔ
+بشری
+چهارده
+۱۳۰۰
+لیلا
+بدیهی
+مابین
+مثنوی
+ویدیویی
+محققان
+رابط
+تلمبه
+پرفروش‌ترین
+استیو
+ساختمان‌های
+وانتشار
+معترضان
+وحی
+برنامهٔ
+بگم
+عسل
+پرتغالی
+فصلنامه
+عجب
+رفتارهای
+وورتمبرگ
+امپراطوری
+برون
+شانزدهم
+مدل‌های
+آکسفورد
+فساد
+چیزها
+خبرنگار
+ذره
+کان
+کنیم؟
+دامداری
+هی
+عبدالکریم
+کوهرنگ
+آنتونیو
+ایرادی
+۱۱۶
+دریافتی
+هرمز
+آب،
+گـپ
+ویکی‌پدیایی‌ها
+۱۰۶
+غریب
+دلفان
+راسل
+۱۹۰۷
+گویم
+قزاقستان
+وحشت
+منشور
+انتقام
+مشروطیت
+کیفی
+بپردازد
+براى
+شركت
+تعصب
+ویلهلم
+خطای
+متقابل
+۲۰۱
+اشکانی
+می‌کرد،
+بروجردی
+طبقات
+طالبان
+سفارش
+فیلمهای
+آهنگ‌های
+کنستانتین
+پیوستن
+دیدگاه‌های
+چالش
+ستایش
+نقشی
+کهریز
+منطقه‌های
+خلبان
+تنگستان
+فروند
+حج
+خاتم
+۱۳۴۱
+گردند
+پایتون
+گفته‌اند
+دانسته‌اند
+دانشکدهٔ
+تکلیف
+بازرگان
+نتوانست
+بیوگرافی
+۱۵۰۰
+بنت
+مری
+نقص
+فانتزی
+پژوهشگر
+دویچه
+کنت
+قاجاریه
+دوام
+حیدریه
+جیمی
+پویانمایی
+قوای
+می‌آورند
+کامران
+متنوع
+استراتژی
+شمارش
+۱۹۰۴
+اعم
+داراي
+بهبهان
+الدوله
+تخلف
+فراری
+ایزد
+رأس
+انداخت
+چرداول
+پیش‌فرض
+رهنمودهای
+بافتا
+شناسان
+اردو
+آبیاری
+ترانه‌سرا
+روحی
+ادیب
+فلات
+ایست
+سلیقه
+ماجراهای
+باکو
+همارس
+تراکتورسازی
+گم
+رابطهٔ
+داشتند،
+رپ
+گز
+بگذارد
+۱۱۲
+مستندات
+زمین‌های
+سایت‌های
+مبحث
+مشکلاتی
+بوکان
+ابزارها
+جبران
+تقریبی
+زیان
+گلپایگان
+خوشنویسان
+۱۲۲
+بارز
+مَا
+بوک
+اشتباهات
+تانک
+می‌شده
+دهه‌های
+واژه‌نامه
+خشکی
+ایی
+اللَّهِ
+عفونت
+۱۲۳
+باده
+نام‌تصویر
+بیس
+كردن
+گچ
+زدهٔ
+طلای
+معکوس
+نبودند
+رضایت
+ثروت
+انار
+کشاورز
+کوانتومی
+اژدها
+سوراخ
+بیلبورد
+شاهین‌دژ
+بره
+اهدا
+زیرزمینی
+تکراری
+صربستان
+مراقبت
+تروریستی
+۱۹۱۱
+متمایز
+آملی
+برساند
+عن
+ابهر
+معتدل
+گفتگوی
+املش
+می‌بینم
+می‌آمد
+۱۹۱۳
+ناشناس
+وله
+جایش
+جنبش‌های
+توليد
+موزه‌های
+نمائید
+دهمین
+برند
+تاریخچهٔ
+می‌شده‌است
+پاسخی
+پشتی
+تشریح
+نمی‌شوند
+خویشاوندان
+انگشتدان
+دكتر
+ژانر
+فریاد
+اخلال
+تمشک
+سعد
+پارسا
+۹۰۰
+نامدار
+نظامیان
+قدری
+حمام‌های
+مستوفی
+گرما
+گرا
+یادگار
+عاشورا
+دفعه
+بیانی
+شنا
+استعفا
+رسانه‌ای
+انحلال
+بزرگداشت
+فایرفاکس
+بتوانید
+مؤلف
+حامیان
+ناحیهٔ
+مور
+۱۹۱۰
+حیاتی
+هرگاه
+آنا
+جاسوسی
+منتج
+جابجایی
+تولیدات
+هاى
+قدردانی
+۱۷۰
+راست۱
+لیلی
+عملاً
+میشد
+کشورهایی
+درجهٔ
+حامل
+ابوبکر
+خصوصا
+اختصار
+مجاورت
+پدیدآورنده
+آراء
+چپ۱
+گله
+یکپارچه
+عبارات
+جمینای
+جزیرهٔ
+اسرار
+خانواده‌های
+بلوز
+مونته‌نگرو
+بیابان
+به‌صورت
+دارید؟
+نقطهٔ
+ضرورت
+وي
+کارکرد
+هوانوردی
+محبت
+پارک‌های
+واژه‌ای
+امامزاده‌های
+هریک
+کوچکترین
+طاهر
+حوالی
+مطهری
+کنگاور
+شدهٔ
+شبکه‌ها
+شیوه‌های
+تیراندازی
+۱۱۸
+جست
+آژانس
+سایز
+بدن۱
+تکذیب
+نقدی
+متناسب
+دال
+بابی
+شانزده
+هرکدام
+ادعاهای
+العاده
+عنایت
+مزدیسنا
+انقراض
+مقدونیه
+۱۲۷
+ندیده
+رأی‌گیری
+دلو
+هندسی
+موبایل
+تورم
+رفتاری
+پیامدهای
+زید
+زادروزها
+حیدری
+بتوانیم
+فوری
+علایم
+نویسه
+غم
+خلال
+اریل
+کاشمر
+بز
+بردسیر
+۱۹۱۵
+حتا
+برخط
+خرمشهر
+همچین
+نفری
+سالگرد
+متخصصان
+شاهرخ
+صحن
+جنین
+جشن‌های
+یکشنبه
+تمیز
+ارامنه
+چپ۲
+جلسات
+مهمان
+کجای
+روال
+۱۳۴۳
+پینک
+سبک‌های
+هان
+بدن۲
+عمودی
+افسران
+شجریان
+نوسنگی
+الاسلام
+مساجد
+صاف
+مروارید
+جانور
+آنهایی
+راست۲
+اسکی
+ناشناخته
+اعتقادات
+یم
+انگور
+ويرايش
+گروههای
+ترانهٔ
+شد؟
+دقیقی
+استادیوم
+مختلف،
+عتیق
+توطئه
+بالا،
+مین
+همگانی
+تلفنی
+می‌دانست
+ود
+ميان
+تشکیلات
+روده
+مدیره
+ونزوئلا
+مخصوصاً
+مشتمل
+انتقادی
+تفنگ
+برایشان
+طالقان
+فرانسیس
+بازارهای
+پایین‌تر
+کاروان
+به‌جای
+الیاف
+خامنه
+خصوصاً
+ظهر
+سکس
+چهاردهم
+ایزو
+مسجدسلیمان
+الکل
+فلاندری
+محمدیان
+شکوه
+کرده‌اید،
+اسلامي
+سم
+کناره
+لوازم
+نمیدانم
+پیامی
+فارغ‌التحصیل
+باس
+کام
+بنویسد
+بازنشسته
+نصر
+کاشی
+شکارچی
+پست‌های
+ویلیامز
+دهکده
+اندر
+۱۵۴
+جهانگیر
+ملکان
+می‌توانست
+عبارتی
+مسئولان
+هلال
+مهندسان
+غارهای
+بیلی
+۱۹۱۶
+بنگلادش
+حملهٔ
+توانستند
+پارینه‌سنگی
+پولی
+خوشبختانه
+نموده‌است
+امینی
+نه،
+هما
+مشورت
+نامحدود
+آندره
+پلنگ
+مخدر
+مضمون
+برمی
+هم،
+لاس
+دهید،
+ویکتوریا
+موثق
+داود
+عذرخواهی
+یاهو
+رنگ‌های
+۱۱۷
+تناوبی
+نوشتید
+لااقل
+شتر
+مرکزیت
+امن
+ترسیم
+سیستم‌ها
+اتومبیل
+آفی
+جون
+خالق
+حرارتی
+رسوم
+موریس
+مارشال
+یورو
+بانو
+اولين
+منشورات
+غیبت
+نوشته‌اند
+قدرتمند
+شکم
+هایش
+انداز
+رویکرد
+علاقه‌مند
+خانواده‌ای
+دمشق
+دربند
+برو
+آرشیو
+۱۹۰۹
+رویش
+استخر
+آنالیز
+گچساران
+بکنم
+مولا
+متفرقه
+رحمت
+شاخ
+۱۳۱۰
+اتفاقاً
+اسمش
+سهامی
+دبلیو
+بخشهای
+سرتاسر
+ویکی‌ها
+خیالی
+نکنند
+تناسلی
+م‍انفی
+جديد
+۱۳۲۴
+کار،
+برندهٔ
+پیچیدگی
+گواهی
+زرتشتیان
+ناصری
+همانجا
+رغم
+گفتهٔ
+۱۱۳
+گرمسیری
+طلوع
+برترین
+درآورد
+به‌دست
+برقی
+سپاهیان
+ویژگی‌ها
+مر
+۱۲۴
+چهاردانگه
+جامعهٔ
+تحقق
+مجاری
+می‌گفتند
+فروپاشی
+چشمه‌های
+ساختاری
+مسافرت
+پیکان
+نرم‌افزاری
+جد
+روشنی
+معرفت
+تله
+می‌کنم،
+محرک
+مشتریان
+بیانگر
+سازمانهای
+چیزهای
+رقیب
+فرعون
+بیروت
+منعکس
+تابناک
+مشرف
+آورده‌است
+نمی‌توانم
+۱۱۹
+مولکول
+نعمت
+می‌رساند
+فرمانداری
+دستکاری
+۱۳۳۹
+مت
+اردبیلی
+مسدود
+بله،
+رانندگی
+۱۲۱
+سایپا
+استعداد
+پیامبران
+داماد
+واجب
+نسخ
+فاضل
+عرفانی
+بزرگ‌تر
+حق‌تکثیر
+شخصاً
+دگرگونی
+عكس
+انبوه
+آپولو
+فنون
+افلاطون
+حمزه
+میانجی‌گری
+نظرسنجی
+آنتونی
+اکوادور
+آن‌چه
+قذافی
+اسکن
+خاتون
+ناگهان
+گونه‌ها
+تونل
+به‌ویژه
+ناگهانی
+بدهیم
+دوشیزه
+آباده
+نمی‌توانند
+شلوغ
+ی،
+۱۳۳۵
+خلع
+فلوید
+ابومسلم
+بایت
+اعطای
+جاسک
+پوند
+پایداری
+تیتر
+واپسین
+استالین
+تعطیلات
+آستین
+مختلط
+تابلو
+خنده
+نویسه‌های
+ثمر
+۲۰۰۰،
+بازاریابی
+حسابداری
+تکلم
+رنگرزی
+نهبندان
+۱۳۳۶
+نیلوفر
+شرقی،
+بداند
+فسا
+آلیکانته
+دیلمی
+اجتناب
+نیر
+سطح‌بالای
+اينجا
+می‌زنند
+کیم
+لغتنامه
+عاشقانه
+فتحعلی
+اشیاء
+تعمیر
+فلانی
+استیون
+سازماندهی
+ویرجینیا
+راجر
+بگویند
+روزنامه‌نگاران
+هندو
+دیوانسالار
+ایستاده
+۱۳۳۷
+کرانه
+کلسیم
+هایدلبرگ
+کرواسی
+سرانه
+الملک
+سنگ‌های
+ژنتیکی
+نیکی
+هجرت
+مامور
+خنک
+نمایان
+بهرامی
+شبستر
+واسط
+آرایش
+مبهم
+بسی
+بریتانیای
+محدودهٔ
+بحث‍
+گاما
+ده‌ها
+نواختن
+فروشگاه
+خمین
+صنعاء،
+کنفدراسیون
+اموال
+هنرپیشه
+پارسیان
+متوسطه
+دامن
+۱۲۶
+لک
+شیشه‌ای
+ابراهیم،
+آمادگی
+هو
+زنجیره‌ای
+۱۳۲۸
+بازیهای
+سنقر
+بدر
+آورند
+مرجعیت
+آلت
+اسدآباد
+کارلوس
+سودمند
+نشانگر
+رسید،
+حوزه‌های
+دیار
+کنگو
+میهن
+کلانی
+۱۲۹
+افسر
+باکتری
+معماران
+۱۳۲
+سیدنی
+کفش
+ارادت
+می‌خواهند
+خر
+۳۵۰
+بدترین
+تاریخ،
+فلسطینی
+زاگرس
+بیاورد
+یانگ
+شخصا
+تشدید
+آدمی
+ماهی‌ها
+هیچکدام
+میناب
+بوسنی
+ایندیانا
+دنباله‌دار
+ملوان
+روزنامه‌نگار
+مؤثر
+دستورات
+رطوبت
+تعامل
+کلان
+عباس‌آباد
+کاملی
+احادیث
+مدرکی
+پاکسازی
+۱۳۷
+تفاوتی
+ورزشکار
+جنبه‌های
+غالباً
+بود؛
+چنگ
+مهاجران
+پله
+تراز
+آمد،
+وا
+کوثر
+وادی
+اتوبوس
+کاظمی
+خبرگان
+موس
+تکمیلی
+لهستانی
+درویش
+منم
+جعفرآباد
+نیا
+جاذبه
+گیلانی
+طلاق
+تروریسم
+به‌خاطر
+آيا
+گرفتار
+اشعه
+می‌پردازند
+شخصیتی
+آقایان
+رفتم
+جریمه
+مهره
+خاستگاه
+میان‌ویکی‌ها
+بالینی
+یزدگرد
+ببرد
+دوش
+چغازنبیل
+۳۰۰۰
+فوقانی
+۱۳۳۱
+گیلکی
+خط‌به‌خط
+کاترین
+بختیار
+کردید،
+گردان
+ادی
+طاها
+مدیترانه
+ارس
+حسن‌آباد
+پوشاک
+بابلسر
+رساندن
+کند؟
+بهش
+وست
+خوشامدگویی
+مهار
+میبد
+فلسفهٔ
+وند
+آش
+سیمین
+خوراک
+خوزه
+ساختند
+نياز
+عروسی
+میگردد
+جلفا
+بودیم
+بکند
+۱۳۸۸،
+روحانیان
+حماسه
+پایتخت‌های
+مبارزات
+احمد،
+ارث
+محمّد
+۱۳۳۳
+کوشک
+سنگ‌ها
+زشت
+دنا
+دستیار
+گرمایی
+ایشون
+نامهٔ
+تحمیل
+گوشی
+دوره‌ای
+ققنوس
+بدانند
+شن
+انداختن
+هفدهم
+غالبا
+اسدالله
+۱۳۴
+شدیدی
+ناپذیر
+۱۴۴
+گینه
+سرمربی
+نطنز
+کیبورد
+محفوظ
+آیند
+انفرادی
+آن‌که
+گمانم
+توانسته
+سال‌شهرشدن
+علم‌جو
+خرده
+درگز
+ایستگاه‌های
+بکشید
+پیش‌بینی
+حالات
+هرکس
+بزودی
+کایروس
+اوستایی
+صفات
+مارکسیست
+خشت
+جنب
+عذر
+ونیز
+آسانی
+کریستین
+صفویان
+اسدی
+۱۹۰۳
+تاخیر
+خیانت
+قوس
+قطره
+آثارش
+سیل
+اسکات
+مشاغل
+شم
+بخارا
+چاپی
+مکتوب
+دیدید
+انتها
+موزیکال
+كاربر
+منشأ
+سمی
+لَا
+پهلوان
+پوسته
+درختی
+مشابهی
+کنیا
+عاملی
+۱۳۹
+گویید
+۱۳۳
+تلاش‌های
+اهمیتی
+عازم
+اسمی
+پکن
+تصوف
+تکاب
+حاکی
+برت
+کنيد
+نوروزتان
+ببیند
+کبوتر
+سفرنامه
+۱۳۳۴
+تخلیه
+آق
+زنجیره
+انتقادات
+کوک
+همان‌طور
+غربی،
+جنجال
+فیزیولوژی
+سانتی‌متر
+بسط
+زخم
+۱۴۱
+ویکتور
+آران
+یك
+التهاب
+دسته‌بندی
+جنگنده
+ایفتا
+ژاک
+طاهری
+فیض
+بهتره
+ادعایی
+اسد
+بودنش
+پیک
+مسأله
+بانوان
+بنفش
+گشود
+باغی
+هیدوچ
+جسمی
+انگشتی
+یوهان
+لنز
+چراکه
+رهایی
+نگرفته
+مقصود
+جوراب۱
+آنهم
+قمی
+سکته
+کو
+سره
+زبانها
+برج‌های
+مکان‌ها
+نشدن
+چابهار
+پاراگوئه
+کتابها
+طولانی‌ترین
+اولویت
+مبارز
+استراحت
+مشت
+حرام
+فرمود
+نقلیه
+کمر
+پستان
+سرچ
+فعاليت
+ارتقاء
+شانس
+خودی
+فاتح
+مطالب،
+گوسفند
+میگویند
+غلام
+وصف
+دلم
+اظهارات
+انتگرال
+سوسیالیست
+گذارد
+ماموران
+بادام
+چال
+ساگه
+ایسنا
+معده
+ریشتر
+اعلان
+تک‌نفره
+بلو
+مناطقی
+شافعی
+می‌گفت
+می‌خواند
+ثانی
+هست؟
+منو
+لوث‌شدن
+جنایت
+برخاست
+بوده‌است،
+نمی‌باشد
+اشراف
+نداد
+مهربان
+الهیات
+همه‌ی
+زمين
+کینگ
+رول
+والتوزیع،
+مدرسهٔ
+ترافیک
+اتهامات
+وای
+بهنام
+شجاع
+سیار
+ترسناک
+ذات
+مختار
+عموما
+اینتر
+فرزندش
+داروشناسی
+ریسک
+۱۹۹
+نیجریه
+مظفر
+حشرات
+میدانید
+جبل
+آریزونا
+نارنجی
+کتابخانه‌های
+میدانم
+آرم
+بشمار
+اعتباری
+کره‌ای
+عکس‌ها
+پیکچرز
+تخته
+متمایل
+رفاه
+شهبازی
+میخائیل
+تطبیق
+نظریه‌های
+بلوغ
+عزیزم
+۱۳۹۱
+محاسباتی
+سنجی
+مکانیسم
+سریعتر
+آبشاری
+کالاهای
+اشک
+خانی
+سازگاری
+مارچ
+گرین
+قرص
+خوانندهٔ
+صفی
+نازک
+داروها
+۳،
+۱۳۶
+هماهنگ‌کنندهٔ
+لینکلن
+بانوی
+خودروی
+پل‌های
+۱۳۳۸
+دیوارهای
+ورامین
+۱۴۵
+اتخاذ
+کمیت
+دارم،
+مذاکرات
+حول
+برگزید
+کارشناس
+نامعتبر
+سفرهای
+رومیان
+ربات‌ها
+غیراینصورت
+انیمه
+به‌وسیله
+استعمال
+صریح
+سازه‌ها
+رامهرمز
+اندیس
+رازقنــدی
+تثبیت
+۱۰،
+تصوير
+گویش‌های
+کتک
+طالب
+حماس
+۱۳۲۹
+علیرغم
+۱۴۸
+حزبی
+استونی
+اوین
+غروب
+حریف
+استراتژیک
+شگفت
+مرگش
+جانسون
+پانزدهم
+موشک‌های
+گن‌آباد
+ارتقا
+باطل
+خورشیدی،
+آلفرد
+ساموئل
+بحرانی
+قندهار
+كردم
+ماکس
+گی
+میخواستم
+بچه‌های
+۱۳۲۵
+شرطی
+گشایش
+زندگي
+دایی
+یون
+فرانس
+تورات
+گزارشی
+۲۲۰
+فیلم،
+دهلی
+مسافران
+سنگر
+نخواهم
+موش
+ریشهٔ
+سخنگوی
+زنگ
+نینتندو
+دیوانه
+بمباران
+مسئولین
+استودیویی
+شدیدا
+تیلور
+۱۲۰۰
+قزوینی
+لاست
+مسلما
+ورق
+شهرزاد
+لطفی
+کلات
+بارداری
+دیواره
+باشگاهی
+شکستن
+تریلر
+ممتاز
+پرانتز
+یوتیوب
+بیهوده
+ابدی
+نباشد،
+کیوان
+طرح‌های
+بدم
+کاریکاتور
+بدتر
+داش
+می‌رسید
+میانجی
+بيش
+اختریان
+سربیشه
+روشنایی
+تبیان
+بکشد
+اراده
+چربی
+خرما
+سلطانی
+شيخ
+مقا
+مستخدم
+وب‌گاه‌ها،
+نشینی
+نرگس
+۱۷۵
+تویسرکان
+خاطره
+برکنار
+غیرقانونی
+ساواک
+نگاره‌ای
+سین
+شناسنامه
+بناها
+‌ها،
+غرق
+شعرهای
+مسلط
+سرش
+اه
+برکت
+جنگل‌های
+سلطه
+اقیانوسیه
+علما
+بنفشه
+یال
+هولوکاست
+دادستان
+حلی
+اجسام
+غواصی
+احاطه
+والا
+بیماریهای
+صدوق
+ریو
+دیویس
+ناهید
+دهها
+نتوانستم
+ایکس‌باکس
+ول
+منبع‌ها
+تاریخی،
+کثیر
+لیتوانی
+شده‌
+بپرسم
+قربانیان
+جانشینی
+سیریلیک
+بوستون
+یونانیان
+دوبار
+فرضیه
+امروز،
+دیده‌ام
+عزيز
+۱۴۲
+میگیرد
+شلوارک۱
+مِنَ
+ارسطو
+ومبلی
+بخواند
+۱۹۰
+صوفی
+صدق
+کارب
+گذاشتند
+هزینه‌های
+فردریک
+نوشته‌اید
+آو
+عمده‌ای
+م‍
+هیچگونه
+حسی
+اللَّهُ
+معدود
+مارکس
+سنگاپور
+رایانش
+عادل
+ریگان
+میرسد
+الگوریتم‌های
+ائتلاف
+فریدون‌کنار
+بازگا
+نگرش
+هرحال
+بدانیم
+کفایت
+فین
+۱۳۲۷
+باورهای
+بازگیر
+لردگان
+چرا؟
+تعویض
+سلجوقی
+جستار
+نخواهند
+می‌نمایند
+دهستان‌ها
+فرمانروای
+خودتون
+منتقدین
+کلاردشت
+اره
+لزومی
+مرتفع
+ویر
+سندرم
+نیاید
+آجر
+دانشکده‌های
+نمین
+مق
+تن‍
+اینچ
+فوتسال
+ساکنین
+‍ه‍
+فرانسه،
+صفحاتی
+۱۹۰۲
+طالقانی
+جعبهٔ
+غارت
+بزرگسالان
+لین
+۱۶۵
+قیاس
+افغانی
+نگذاشته‌اید
+ساید
+نادری
+امامان
+سنا
+سرگذشت
+رایش
+توجیهتان
+بروند
+سمفونی
+آهنگ‌ها
+توس
+تم
+پنسیلوانیا
+خرچنگ
+مغان
+سجاد
+پایینی
+تحریر
+لوث
+شانه
+طوفان
+اصولاً
+کبودرآهنگ
+تسمیه
+عامیانه
+بیشینه
+فضاپیمای
+بودایی
+۱۸۹۰
+اقلیم
+مثالی
+جشنواره‌های
+برایان
+میرود
+پین
+آم
+سرگرمی
+مزایای
+ریال
+رسماً
+ناحیه‌های
+تازه‌ای
+می‌دهیم
+هارد
+مقال
+فراهان
+دلیلش
+میلیمتر
+۱۸۰۰
+ماهنشان
+سالار
+جت
+مردگان
+فقیر
+۱۵۵
+راستا
+میکنیم
+جوری
+شلوارک۲
+پژوهشگاه
+نیستند،
+۱۴۶
+اینشتین
+یخچال
+روزمره
+ارم
+سنین
+تحسین
+سکه‌های
+۱۳۱
+فحاشی
+پاپ‌های
+عینی
+رسانده
+رز
+بودم،
+ارزشی
+ستان
+باراک
+اصلي
+الکتریک
+نامه‌های
+عطار
+علمي
+بخشید
+السلطنه
+يعني
+غلبه
+مستقیماً
+منش
+رستاق
+افراطی
+بگیرم
+سيد
+۱۴۷
+ندارند،
+الَّذِينَ
+نمونهٔ
+کریستال
+قایق
+نوادگان
+سالیانه
+می‌پذیرد
+احترامات
+شیری
+سیاهکل
+سرب
+نصرالله
+مانه
+گیم
+ببر
+آستان
+زیستگاه
+ای،
+داده‌ام
+لوئی
+شریعت
+آموز
+رتبهٔ
+کمک‌های
+نقدها
+حلقه‌ها
+ارتقای
+هال
+انسانها
+پشتو
+امیرحسین
+سین‌آباد
+رشید
+۱۴۳
+شیرینی
+مذاکره
+تعدیل
+کارمند
+اعضاء
+روانه
+بنر
+معروفترین
+خیابان‌های
+مشاوره
+اکثرا
+افت
+کنگان
+بگذارند
+دامنه‌های
+رحم
+بیدار
+تیپ
+تنفس
+افغانستان،
+میشیگان
+استعمار
+فرخ
+گذرگاه
+توالی
+تایم
+جمله‌ای
+ولادیمیر
+دستوری
+تساوی
+ساختارهای
+جانوری
+قسم
+۱۳۱۶
+هفده
+یقین
+صوفیان
+می‌نویسند
+رومرکز
+بک
+انگشته
+مولف
+نگفتم
+یورش
+ثبات
+بیایند
+بپرهیزید
+وبا
+اس‌جی‌اچ
+جن
+ورزش‌های
+لامرد
+سپیدان
+کبک
+عزت
+افشین
+کامرون
+فیلم‌شناسی
+پاول
+نکنیم
+درگیری‌های
+رخداد
+کیا
+عرف
+شازند
+یکصد
+استهبان
+می‌گیرد،
+نرسیده
+ویژهٔ
+ابتلا
+اینطوری
+گارد
+بزن
+مدتها
+وعده
+شرف
+پيدا
+نیدرزاکسن
+زواری‌جان
+اسدخانی
+هندواروپایی
+تصویرگر
+مختص
+استادی
+هیپ
+امشب
+احیای
+بنو
+امامت
+خونریزی
+سیگار
+کاسه
+غرض
+معتقدم
+ساختم
+صفح
+روایتی
+نمادهای
+متوالی
+خدایی
+نمود،
+عجم
+آبهای
+آمده‌اند
+نموده‌اید
+لاریجانی
+شیوع
+زمينه
+الا
+بیا
+آزمایشگاهی
+آنتن
+قرآنی
+بیستون
+فاجعه
+۱۵۸
+ریه
+انعکاس
+تقلب
+هجدهم
+طبرستان
+تناقض
+مدت‌ها
+علمی،
+تصنیف
+فروغ
+دایرةالمعارف
+آلمریا
+تاسیسات
+گونهٔ
+هیچکس
+ایدز
+آوا
+۱۴۹
+مديريت
+بیاد
+پایگاه‌های
+زیرصفحه‌های
+مقاوم
+گمشده
+نشدید
+نوزاد
+سیف
+دیفرانسیل
+موافقان
+بانه
+فونت
+صفا
+واتیکان
+اصالت
+کتابخانهٔ
+یگانه
+کیت
+ترجیحات
+کنوانسیون
+نانو
+۱۵۳
+آنزیم
+كردند
+تیمی
+۱۸۵
+هستید،
+حوض
+نویسنده،
+ورد
+حسنی
+پديا
+بویین
+مادها
+ناوگان
+بنگاه
+اردلان
+صومعه
+تورنتو
+کارولینای
+۵۰۰۰
+اشکالات
+مسائلی
+انداخته
+نماند
+دستمزد
+بخواهم
+سرقت
+میدانی
+ریتم
+خوبیدگی
+پوستی
+اندی
+الماس
+بزنم
+مقدونی
+هسن
+گروه‌ها
+بروجن
+تگ
+منشی
+ملکی
+تبعیض
+ببین
+افق
+خشن
+کورین
+دوی
+قوام
+ایلینوی
+بچه‌ها
+تکاملی
+دخترش
+برانگیز
+اصطلاحی
+مل
+یکان
+داراست
+عرب‌ها
+ناموفق
+کبد
+کوفی
+رودها
+پشته
+رسالت
+مرتکب
+معروف‌ترین
+نشوند
+نبودم
+بنیانگذاری
+لیبرال
+فرید
+حوضه
+ربع
+نوح
+سیاهه
+تای
+خستگی
+پدری
+برنامه‌ها
+فرستادن
+بیطرفی
+نواب
+نزول
+استیشن
+رادار
+پخش‌کننده
+سازند
+عضلات
+سعیدی
+کوین
+بنویسند
+برم
+بیایید
+حجازی
+شده؟
+تالیفات
+حسینعلی
+نیست؛
+مزاحم
+فروشی
+آموزان
+میکرد
+۲۴۰
+بحث،
+وارنر
+کوری
+واکنش‌های
+فستیوال
+قارچ
+لغت‌نامه
+تاجیک
+شرکتهای
+هروی
+ویژگیهای
+عکسهای
+چارلی
+باشيد
+داشتیم
+بومیان
+باقیمانده
+یافت،
+اشاره‌ای
+فصلی
+عبدی
+بزرگوار
+بیتی
+مُعجَم
+نازل
+امپراتوران
+مهمتر
+کانی‌ها
+۱۸۹۶
+محمدباقر
+شایع
+ادریس
+که‌
+دهندگان
+اعلامیه
+به‌نظر
+داروی
+لیک
+اتوماتیک
+مي‌شود
+فروغی
+برآورده
+بلا
+آدولف
+قشقایی
+تنفسی
+اردوگاه
+زنجانی
+تنه
+گزیده
+مریوان
+پورنو
+کامبوج
+تل‌های
+رمزنگاری
+دامپزشکی
+شاهنشاه
+قرقیزستان
+ارابه‌ران
+نمودم
+ضرر
+بازنگری
+دگرگون
+بررسي
+شده‌بود
+ناپدید
+متاسفم
+نسخه‌ای
+اشنویه
+پیاپی
+عبدالعزیز
+۱۶۸
+اسباب
+نسبیت
+کعبه
+مردم،
+ذوب‌آهن
+آنچنان
+ادرار
+رنسانس
+سوسیال
+دهخدا،
+تختی
+فاطمی
+ماشین‌های
+پاسکال
+مینا
+تابعی
+سایتی
+توانیم
+ترين
+توران
+ادارهٔ
+فهرست‌ها
+خوشی
+معینی
+یادآور
+مخالفین
+دود
+مدام
+انی
+تقاطع
+پتاسیم
+نساجی
+ارد
+اندیمشک
+داده،
+مخالفتی
+دونفره
+اندیشه‌های
+علیزاده
+آجری
+برسیم
+اقدامی
+فقهی
+اشکان
+همبستگی
+فرادیرینه‌سنگی
+گناوه
+کوفه
+۱۸۹۹
+اینصورت
+عبدالرحمن
+لبه
+بی‌پایان
+میدهند
+منشا
+مرحلهٔ
+بیطرف
+کردید؟
+مسخره
+مشخصه
+عضلانی
+اسارت
+عنوانی
+۱۵۲
+ندارم،
+برچسب‌ها
+اچ‌آی‌پی
+منصوری
+۲۱۰
+بینم
+مجنون
+تعاریف
+تعهد
+اقتباس
+جلیل
+می‌کنید؟
+رزن
+مسئلهٔ
+فرستنده
+گان
+قاب
+کمونیسم
+تناسب
+ندای
+توحید
+هواشناسی
+کرده‌اند،
+منتها
+روز،
+شوال
+لیزر
+پس‌از
+دزدان
+دارد؛
+جنگ‌افزار
+جایزه‌های
+واحدی
+تیموریان
+ذكر
+کنده
+ترش
+می‌خوانند
+ریش
+تمایز
+پیشبرد
+زندگانی
+دلتا
+پیش‌از
+نقده
+ایرلندی
+هنرستان
+قبال
+فرصتی
+دودویی
+عليه
+زیباترین
+شاعری
+سرما
+ایلی‌نوی
+شهبانو
+پنالتی
+بهاری
+افتد
+فیروزکوه
+فایده
+۱۶۳
+بروس
+نیسان
+نکردند
+نمیتوان
+۱۶۲
+روباه
+سقراط
+کشته‌شدگان
+اورانیوم
+عملا
+طراحان
+ماهیچه
+سرم
+اوهایو
+علاقمند
+نویسد
+الجزیره
+گذشته،
+مزارع
+گزینش
+جنگهای
+اطلاعی
+نوشته‌ها
+پارلمانی
+۱۱،
+جنابعالی
+اسفندیار
+امیدوار
+ک‌گ
+گازهای
+کبود
+زمین،
+تلگراف
+لئونیداس
+گرمای
+کتابخانه‌ها
+آشوری
+طعم
+راد
+زنانه
+عربی،
+جادو
+حمیدرضا
+جنگ،
+جابجا
+ماکیان
+بیابید
+شکاف
+گلزار
+متفقین
+متاخر
+سایتهای
+بایگانی‌ها
+بهره‌برداری
+جنایی
+کارون
+شهدای
+میامی
+پدیده‌های
+هستم،
+برکلی
+نایین
+ببینند
+استانداری
+۱۶۱
+پسری
+شوالیه
+کت
+شاخه‌ای
+مقاطع
+آنوقت
+اسکو
+۱۸۹۲
+نده
+رسانید
+۲۳۰
+تاسف
+هايي
+پلدختر
+تاجیکی
+جاجرم
+وضع‌کننده
+استر
+همنشین
+زحمتی
+کانادایی
+تبلیغات،
+زهک
+دولت‌های
+ترمودینامیک
+سوری
+خلفای
+درآن
+فراگیری
+ختنه
+امیرآباد
+تروث
+بوم
+زاد
+خنج
+بروم
+سومالی
+جیم
+دیجیتالی
+عفو
+سوشی
+اصفهان،
+بلاندی
+کوچک‌تر
+گمنام
+سکوی
+نزاع
+احتیاط
+گردید،
+بزنند
+علنی
+ویلا
+۱۳۲۶
+الهه
+هدر
+ظلم
+ناو
+می‌کردند،
+الحکمة،
+یاقوت
+حتي
+شرکت‌ها
+تعلیق
+خواستند
+کاروان‌سرا
+نکتهٔ
+رشته‌ای
+باهم
+بپردازند
+درجات
+وجودی
+بودا
+نیوتن
+منطبق
+نصرت
+ال‌جی
+سومی
+فلش
+۱۳۸۵جمعیت
+فریم
+دوما
+ساقه
+اسماعیلی
+دینامیک
+المقحفی،
+المُدُن
+فیلم‌هایی
+فیزیکدان
+محضر
+آخوند
+فراهانی
+صید
+بسا
+الیَمَنِیَة
+بنایی
+۱۷۳
+می‌گوییم
+درآمده
+مورخان
+یونیکس
+جاها
+وام
+کوتوله
+۱۷۶
+ژرفای
+موجودی
+مرادی
+بدنیا
+پمپ
+پرستاری
+می‌شوید
+مناره
+انقلاب،
+برجستهٔ
+جذاب
+نوشتارها
+نمیشه
+مایک
+امیری
+چناران
+ــ
+گردو
+تفویض
+دخیل
+۱۵۹
+بنیادین
+بدیع
+سالیان
+مواضع
+وَالقَبائِل
+۱۶۹
+می‌بیند
+درگذشتهٔ
+داشته،
+قنطورس
+۱۸۹۸
+تصمیم‌گیری
+مشمول
+رودان
+فراگیر
+آمده،
+نفهمیدم
+۱۸۸۹
+شده‌اید
+نفی
+افسردگی
+می‌دانستند
+آلات
+قوت
+دانه‌های
+محمدحسن
+عزيزی
+جامی
+نجم
+طرحی
+گاندی
+جنوبی،
+بصره
+اروگوئه
+شرکت‌ها،
+پورت
+خجسته
+زمانیکه
+ریشه‌های
+فمینیسم
+گاردین
+بایست
+وار
+دیوان‌سالار
+فوتبالیست
+۱۶۷
+آلمان،
+شعله
+آناتولی
+على
+شمالی،
+سیمون
+ظروف
+رستوران
+دایر
+می‌گذارند
+تفاهم
+آناتومی
+گذراندن
+شكل
+مرگ‌ها
+آهنگسازی
+لیتر
+دزدی
+فرموده
+معصوم
+اطاعت
+تارنمای
+فارس،
+پلان
+هانس
+فریدریش
+ملی،
+روحانیت
+اوّل
+نتيجه
+وادار
+صورت،
+۱۳۰۴
+ترتیبی
+مبارکه
+بنیان‌گذار
+۱۷۹
+ژوزف
+اردستان
+افزودم
+مطبوعاتی
+ارز
+جنجالی
+نوازندگی
+سوزان
+دارن
+افتادن
+هایشان
+تحقیقی
+سهند
+سپاسگذارم
+فیزیوتراپی
+محافظ
+ماشینی
+ربر
+یدالله
+میمون
+سیاستهای
+نگارهٔ
+چه؟
+صراحت
+رسته
+تجویز
+توفیق
+مغولستان
+کین
+وال
+ساکورا
+پیشروی
+متوفی
+تازی
+دیلم
+پل‌دختر
+می‌خواست
+صدیق
+نمی‌بینم
+ایلات
+درحالی
+غلات
+نوه
+هاله
+سیستمهای
+کتیبه‌های
+سیال
+منبر
+بیک
+۱۳۱۴
+۱۳۱۸
+حسين
+۱۷۱
+درشت
+سوق
+برنامه‌ای
+گهواره
+دست‌آوردهای
+تعبیه
+رادیوی
+ساسان
+درامز
+۱۲۹۹
+تجسمی
+سیمان
+گنجی
+کشش
+اسلوونی
+ویلسون
+داماش
+إِنَّ
+کارتوگرافی
+کاشت
+دستان
+لید
+نوازندهٔ
+نمی‌شد
+قران
+ایدئولوژی
+کامپکت
+ناغان
+قرائت
+کاراکتر
+خانه‌ها
+شفاهی
+فله‌ای
+شهرسازی
+اعتصاب
+۱۸۱
+ویدیو
+شايد
+ویرایشگر
+پردازد
+داده‌اید
+حاد
+اجتهاد
+مرطوب
+کلماتی
+مهریز
+حلال
+بیافزایید،
+۱۵۷
+همجنس‌گرایان
+لینکی
+تطابق
+باورند
+دالاس
+إِلَّا
+اصولی
+کپی‌رایت
+الفبا
+کیهانی
+تاب
+شرعی
+محتوی
+هانری
+می‌دهند،
+یوگسلاوی
+بگذارم
+تداوم
+گریز
+نشده‌اند
+شناخته‌شده
+انعطاف
+اندک،
+دعوا
+کری
+تبیین
+احساسی
+ساعات
+معاصر،
+پیشوند
+طبع
+میاندوآب
+اخترفیزیک
+مطمئنا
+پرسید
+انگل
+برکناری
+رولینگ
+حفاری
+زیارتگاه
+منتسب
+پیام‌های
+گسسته
+طريق
+باخ
+۱۳۲۳
+کلیساهای
+معصومه
+شهروز
+متناوب
+۱۸۹۵
+پن
+ابراهيم
+۱۳۱۳
+بطوریکه
+رابین
+آموخته
+میدان‌های
+تاریخ‌نگاران
+بکر
+میش
+پخته
+قلمداد
+رویا
+باشید،
+سیستانی
+قومیت
+جرمی
+لوس
+آفرین
+تلف
+خوارزمی
+محتوایی
+سول
+دبط
+جُستارهای
+می‌نمود
+روزنامه‌ها
+یت
+دگر
+بانکی
+سدان
+متغیرهای
+یابند
+بکارگیری
+انتاریو
+کوسه
+۱۶۴
+بلخی
+بیم
+خلخال
+حائری
+۱۸۹۳
+آورده‌اند
+نقطه‌ای
+علمجو
+استیل
+سلولهای
+گوگرد
+میتوانند
+گوارش
+سبزی
+۱۶۰۰
+جوراب۲
+زیرین
+ميشود
+پنبه
+آورد،
+حرفهای
+لنگرود
+فریمان
+سلاح‌های
+میانگین‌جریان
+غبار
+مردانه
+مؤسسهٔ
+اسراییل
+تک‌نواز
+۱۶۶
+لکی
+خبرنگاران
+پالایشگاه
+مصلحت
+۱۷۷
+مجروح
+پرستش
+دوگانه
+مدفون
+ولیعهد
+سرزمینی
+آق‌قلا
+اساسا
+بهر
+ملي
+كنار
+روستاي
+کلاس‌های
+سفره
+نرمال
+وری
+کیف
+۱۸۸۰
+۱۹۸
+زدید
+زراعت
+رهنمودها
+توضيح
+۱۷۲
+۱۹۲
+پدیدار
+وایت
+بمانند
+لرد
+دستم
+ایسلند
+لیقوان
+نیافتم
+باتشکر
+تئودور
+عبادت
+تبديل
+نکردید
+مسلحانه
+دیزنی
+رانش
+فرهنگ‌های
+مخاطبان
+دول
+کتابت
+سلیم
+ایرانی‌تبار
+غلظت
+شونده
+۱۲،
+اوراق
+سامانی
+اقتصادی،
+۲۵۰۰
+شخصیت‌ها
+فحش
+سربازی
+هشداردهنده
+ندرت
+۳۲۰
+می‌شه
+۱۸۹۷
+فروهر
+صلی
+سیوند
+انجمن‌های
+بعلاوه
+ترشح
+فرج
+جاي
+بخیر
+محراب
+کارتان
+هجده
+قریه
+ربیع‌الاول
+ضخامت
+بارندگی
+بح
+نسیم
+زهره
+جادویی
+تالاب
+جنون
+بروی
+۱۳،
+فیلد
+کریسمس
+میزبانی
+می‌کنید،
+آپلود
+برگزیدگان
+یش
+خانواده‌اش
+کریستوفر
+بیننده
+توکلی
+می‌سازند
+لنگ
+تداخل
+مقدمات
+۱۸۹۴
+الوند
+مع
+گناباد
+مزدا
+رکن
+عیلام
+ترقی
+منکر
+معامله
+اینچنین
+کول
+سازمان‌ها
+مأموریت
+موعود
+دولت‌آباد
+بلبل
+طولی
+می‌رسند
+اجاق‌کندی
+ديگري
+ندارد؟
+براین
+مصور
+اعتقادی
+فرخزاد
+درباره‌ی
+خداآفرین
+گفتاری
+خوانی
+پارامترهای
+تهاجم
+آیوی
+توضیحاتی
+بشرویه
+۹۷۸
+کیست
+نداشت،
+شهروندی
+برخي
+۱۵۶
+سمرقند
+نوا
+كمك
+لامپ
+عماد
+رام
+اينکه
+ضمیمه
+بنابراین،
+تصویربرداری
+سیبری
+یوفا
+کلر
+گوجه
+حیف
+سواری
+۱۳۱۲
+طارم
+۲۶۰
+اباد
+عنوان‌های
+مركز
+مقوله
+گوستاو
+مرعشی
+بحر
+تون
+انصار
+جداسازی
+تصفیه
+سازندگان
+ببنید
+محافل
+نقره‌ای
+تیرماه
+پیاز
+سرسبز
+انه
+چشمان
+تایباد
+اشیا
+طرد
+گوهر
+نکن
+هرزگوین
+اقلید
+خاص،
+ثالث
+علی‌رضا
+آنگونه
+مستمر
+عضوی
+هامبورگ
+پورتال
+تویوتا
+رامیان
+هخامنش
+اردل
+قاطع
+گنجینه
+روشنفکران
+تصادف
+۱۹۷
+جزیی
+مؤسس
+روبروی
+آلاسکا
+خوشه‌مهر
+آرد
+صالحی
+سونامی
+کشیش
+پروس
+انحصاری
+کاسته
+دوستانش
+گاوران
+دلالت
+۱۸۴
+اصحاب
+جزیره‌ها
+مهدوی
+آبیک
+افزايش
+مزیت
+جوابی
+صغیر
+منحنی
+رمین
+سانتیگراد
+دبیرکل
+غریب‌دوست
+بنزین
+اپیزود
+استانهای
+بهاءالله
+سپید
+کمونیستی
+سوگند
+شهباز
+اکتشاف
+استحکام
+مفاد
+بسازد
+اسکناس
+۱۴۰۰
+مبدأ
+بخورد
+مناظر
+زا
+پرستی
+تمبکا
+محرمانه
+سکنه
+زیتون
+رومانیایی
+جسارت
+عمومی،
+دات
+آهنی
+بینید
+مخابراتی
+نظرش
+مولداوی
+العظمی
+ولف
+ممکنه
+راننده
+اولاً
+وَمَا
+وسیله‌ای
+موی
+بادلو
+چرب
+مسافت
+مکس
+۱۷۸
+پودر
+عوام
+که،
+پنجم،
+گرگوری
+میسر
+مفصلی
+استبداد
+حیدرآباد
+آلیس
+فیروزه
+ریخت
+اینان
+کروی
+وقف
+شعارهای
+۱۹۶
+سملقان
+فروخته
+۱۷۴
+نبوده‌است
+دیکتاتوری
+میدهم
+ظریف
+معتبرترین
+سیاسر
+ایرادات
+اجماعی
+۱۹۳
+منحل
+زاید
+میخواهم
+صاحبان
+مهلت
+می‌پرداخت
+ماهه
+جری
+بازرس
+وَلَا
+گلشن
+برهنه
+نوشته‌ام
+می‌شود؟
+صخره
+عمو
+ابد
+بیداری
+۱۸۸۸
+۲۷۰
+بعلت
+پنیر
+حاتمی
+خانقاه
+رس
+شکسپیر
+معذرت
+پايان
+ساختگی
+آموختن
+فقدان
+پاسخگویی
+زانو
+كوه
+لزوما
+قمر
+شهریاری
+بيان
+واین
+صورتیکه
+بدنبال
+پاره‌ای
+ارمغان
+می‌شود؛
+شغلی
+دیگ
+عنبرآباد
+امریکایی
+پیشرو
+تجربیات
+علوم،
+پیری‌کندی
+ازجمله
+به‌نام
+صومای
+۳۳۰
+۲۶،
+اسطوره‌های
+منفجره
+دستتان
+رشته‌کوه
+۱۹۵
+برن
+بلده
+شیعی
+رحیمی
+رجایی
+کجور
+۱۵،
+تاون
+آموزگار
+آستارا
+هیل
+ترانه‌ها
+یوری
+کلاله
+محو
+خوانندگی
+زار
+عیب
+افسانه‌های
+پخت
+نامبرده
+پنجشنبه
+سور
+نروژی
+تکنیک‌های
+دریاچه‌های
+مالدیو
+سوسن
+کیسه
+کاوش
+دابودشت
+کردن،
+زندگان
+مقدمه‌ای
+موزهٔ
+۱۸۸
+برپایی
+داگلاس
+فضل‌الله
+زینب
+اللَّهَ
+صحرایی
+کرت
+اذیت
+نمی‌رسد
+آتشفشان
+۱۳۲۱
+بلاروس
+انگ
+ارگان
+بسامد
+نشوید
+بزرگای
+کلارک
+۲۱،
+بشدت
+نقوش
+خوشنویس
+الفبایی
+نخ
+رفیق
+ناراحتی
+رسی
+بخواهند
+طرفداری
+دردسر
+۴۵۰
+۱۸۳
+ایرباس
+پرت
+فرآیندهای
+گردشگران
+مخرب
+میگم
+کارتون
+نوژن
+سفری
+صندلی
+می‌کرده
+نزنید
+ج۱
+میخواهید
+گنگ
+می‌ریزد
+پشتکوه
+ویکی‌پدیاست
+دلاری
+ویکیفا
+خيلي
+بازگشایی
+چشمگیری
+نیتروژن
+بافی
+لانه
+بدید
+آشتیانی
+باشد؛
+محققین
+۲۴،
+یوتا
+طرفه
+توسعهٔ
+کشتی‌های
+۲۰۶
+جاستین
+شوشتری
+اسمیت‌سونیان
+طوطی
+عباسیان
+رده‌ای
+زرند
+می‌رود،
+ابتکار
+دهلران
+بستان
+برجای
+۳۸۰
+رمانتیک
+ترجمه‌های
+کاربرها
+بندری
+پرداختن
+منهتن
+پاتریک
+طناب
+چهارم،
+نتواند
+بور
+دانسته‌های
+روحیه
+میلاد،
+برزنجیر
+مرجان
+دهند،
+شهرستان‌ها
+سپرد
+داران
+استوارت
+دوچرخه
+طراحي
+۱۱۰۰
+خانه‌ای
+نوآوری
+نامنظم
+کامپیوترهای
+دیوانسالاری
+وفادار
+هرودوت
+امسال
+استثنا
+فرانکفورت
+مجالس
+خدمتتان
+کتابداری
+لاین
+پوران
+آنالوگ
+برادوست
+۲۰۸
+شادباش
+می‌شناسند
+بولکیمده
+می‌نویسم
+چالدران
+کهنوج
+تطبیقی
+۱۶،
+دیدگاهی
+منحرف
+شنوایی
+تیز
+تیغ
+موشکی
+پرشیانا
+امیل
+ایزدان
+سه‌گانه
+پنجه
+۱۸۹۱
+۱۳۲۲
+دين
+قبله
+جهنم
+خدماتی
+ببرند
+مأمور
+نیستیم
+کلمه‌ای
+اعتیاد
+فرانکلین
+معجزه
+ذهنم
+بازماندگان
+مصوبه
+کلینتون
+برسند
+معاهده
+نمیکنم
+چندگانه
+شهرستانی
+لاک
+موضوعاتی
+خوسف
+اسک
+خروس
+لتونی
+وات
+کرد؛
+رودکی
+خدمتم
+تاری
+مجلسی
+فهمید
+هفتگی
+کروز
+برگرداننده
+قیصر
+معروفی
+فكر
+نو،
+فضانورد
+فتح‌آباد
+هورمون
+الفاظ
+آمازون
+بیاوریم
+دستهٔ
+می‌کردید
+بینایی
+پافشاری
+بردم
+دیپلماتیک
+سنگینی
+نمره
+غیرآزاد
+فریب
+پذیرد
+حیطه
+اصلی،
+تربیتی
+محال
+ارجمند
+می‌یابند
+فلج
+اربر
+اینجا،
+آوای
+دودانگه
+چاه‌بهار
+همزه
+۲۳۸
+تمبر
+انوشیروان
+متن‌های
+پشتوانه
+عجب‌شیر
+قسمت‌ها
+آشوب
+بدرود
+نظرشان
+ه‌های
+روزتان
+استفان
+گیتاریست
+نشده،
+دینار
+چاره
+تیموری
+زهی
+مغولی
+۲۵۶
+هیوستون
+الموت
+۱۸۷۹
+راگبی
+لوکزامبورگ
+حیث
+عاج
+سخت‌افزار
+رمانی
+نگهبانی
+پتروشیمی
+چادر
+صلیبی
+کنکور
+کانسار
+بلوچ
+زاهدی
+هستید؟
+دوبله
+طیفی
+نشریه‌های
+زنبور
+حزب‌الله
+اخوان
+اجزاء
+ژنو
+دعای
+مزمن
+سخنی
+نهایتاً
+اندرو
+میشوم
+۱۸،
+دارمشترانگ
+می‌دارند
+سه‌شنبه
+حفره
+زرندیه
+ذخایر
+۱۳۱۹
+زنجیر
+سبکی
+قیمتی
+جنیفر
+۲۰،
+تعمید
+آبگرم
+حکمرانی
+پلاستیک
+بی‌نزاکتی
+تماشاگر
+لایحه
+بازه
+تحکیم
+موضعی
+جویی
+محافظة
+شاه،
+ما،
+۳۰،
+آمبرلا
+کلرادو
+هیجانی
+مجتهد
+گیاه‌شناسی
+اضطراب
+جنگ‌افزارهای
+۱۹،
+ادوار
+مسیری
+چمران
+پایه‌های
+گیتاشناسی،
+نمی‌کنید
+گیل
+متین
+آدلر
+۱۷،
+بعدش
+باکس
+یاس
+حکمیت
+کیلوبایت
+بریده
+هموار
+معقول
+کروم
+۱۸۸۶
+غزنوی
+نوش
+بازنشستگی
+گوینده
+یک‌نمونه
+هنر،
+میاد
+عظمت
+جهش
+جانبداری
+شبكه
+آسا
+استاندار
+۲۰۹
+فرانسیسکو
+بریتنی
+محدودیت‌های
+بشکه
+بنگرید
+تاثیرات
+آسفالت
+گیج
+کاروان‌سراهای
+فراموشی
+گلدار
+ترتیب،
+يافت
+همینجا
+بدخشان
+۲۵،
+تمدید
+زيادي
+هستش
+رضا۱۶۱۵
+بودی
+مهرماه
+اسکندریه
+لزوماً
+سیستمی
+هارون
+نگفته
+می‌دانیم
+سایوز
+آن‌را
+نوزده
+بمبئی
+فان
+میدانند
+۱۸۷
+دانستند
+اجاره
+فورت
+مراقب
+نفرت
+نوی
+۲۰۴
+تدریجی
+تهی
+نورآباد
+گزاره
+کلامی
+نتیجه‌ای
+پانک
+هاكل
+عفونی
+بسر
+پیشگامان
+بلاغ
+زئوس
+بريفين
+گزارش‌های
+نمایندهٔ
+سیالات
+۱۸۲
+فارسان
+جلدی
+فلک
+تحقیر
+فهمیدم
+ناتو
+سایرین
+شناور
+انستیتو
+نیکو
+مارکسیسم
+تبعیت
+تفریح
+زبان،
+گلوگاه
+بقیهٔ
+کمپین
+احراز
+بودن،
+محکومیت
+کماکان
+بستری
+تروریست
+سرواژهٔ
+دانمارکی
+آمستردام
+همی
+داوید
+کافیست
+دنی
+رون
+۶۰۰۰
+لابد
+کانتری
+سس
+کسری
+می‌فرمایید
+سیاستمدار
+حریم
+معنویت
+عسکری
+بخشیدن
+محصور
+مدافعان
+گرایش‌های
+واگن
+حجر
+سرداران
+مشهود
+یافتم
+تنسی
+نهر
+دارالفنون
+نمايش
+بسياري
+سابقهٔ
+یتیم
+توپولوژی
+۱۴،
+نگارشی
+جمعيت
+تنبیه
+کیو
+سقط
+شریفی
+کما
+میکروبیولوژی
+دیابت
+تاتنهام
+منقرض
+تاتی
+محمددین
+انگليسي
+فارسی‌سازی
+زمینهای
+شهدا
+۰۸،
+متکی
+کوه‌ها
+دزد
+کنایه
+مشایخ
+ارزان
+ماسه
+هرمان
+تنظیمات
+اونجا
+خار
+هیلاری
+چنار
+خزانه
+شکاری
+عجایب
+رنو
+قراردادن
+جابر
+سروستان
+مستطیل
+مجموعه‌ها
+بهمیی
+یکسال
+سرخرگ
+نادرشاه
+لیاقت
+دوستار
+وارده
+کاستیا
+لرزه
+اى
+بجا
+نم
+مغولان
+امارت
+کشاورزان
+طبی
+کجاست؟
+نبح
+نمایم
+للطباعة
+بکنند
+داستان‌ها
+آمیخته
+تاريخي
+اندازه‌ای
+پیکار
+مستعمره
+کوهپایه
+تصدیق
+۱۳۱۵
+فیلترینگ
+۰۹،
+آدینه
+توبه
+بصری
+بکنیم
+هوتک
+فیلم‌نامه
+پشتون
+زمره
+حبیبی
+اسکندری
+نیایش
+هائی
+رقابت‌های
+داوطلب
+ازش
+بنظرم
+دلیجان
+رضی
+مصاحب
+پرون
+بازگو
+آگهی
+قولی
+سیسیل
+انگلیسی‌ها
+مکاتب
+حبیب‌الله
+سانسکریت
+توکل‌آباد
+نموده‌اند
+حیوانی
+پروژه‌ها
+گیتی
+فالتز
+سنگسار
+بخت
+میلانی
+مارکوس
+نید
+شدیم
+۲۲۴
+مش
+فصول
+کتابش
+می‌خواهیم
+مشی
+آنی
+مادهٔ
+میکردند
+یکا
+طلبان
+عهدنامه
+الملل
+ارکان
+کاربریتان
+جلال‌الدین
+ایرونی
+یونس
+آبراهام
+فرشتگان
+فارسی‌زبانان
+۲۰۳
+۳۵،
+ناتمام
+موظف
+ایت
+می‌زنم
+ییلاق
+منی
+كم
+گریه
+بسازیم
+سیبک
+انجا
+موفق‌ترین
+۱۳۰۷
+ثروتمند
+گریخت
+زمان‌دار
+تروا
+ژرمنی
+برنارد
+تشكر
+ژنریک
+راهبردی
+گره‌های
+پارسی‌گوی
+بندهای
+مبادله
+اسفندیاری
+سرتیپ
+خوارزم
+کلاغ
+ياد
+ايراني
+نجف‌آباد
+سولفات
+كامل
+ناظری
+شهرستانهای
+أَنْ
+میگ
+پادگان
+مرتضوی
+زياد
+کلود
+مقاصد
+بهارستان
+دیکتاتور
+باستان،
+۳۱،
+اسکای
+الکلی
+میباشند
+پارتی
+بیاورند
+لایه‌های
+پرتقال
+آمیزی
+۴۰،
+۱۸۶
+رستاخیز
+خرگوش
+فیبر
+لیبرالیسم
+مخترع
+تعمیم
+برمی‌گردد
+تل‌آویو
+خورش
+مولد
+ستم
+باغات
+نژادهای
+ضربات
+آنست
+ارواح
+جوار
+اپرای
+تحتانی
+آنتوان
+زحمتش
+۱۸۸۲
+بازگشتی
+رفت،
+۱۸۹
+هوگو
+گیلاس
+۲۰۵
+دستاوردهای
+قضائیه
+۴۰۰۰
+مستقلی
+رعنا
+بخوان
+۵۶،
+سوزی
+تلاشی
+هرکسی
+میلی‌متر
+هفته‌نامه
+برومند
+کباب
+سرمایه‌گذاری
+پلاتین
+دنیس
+وگاس
+قرآن،
+نصرت‌آباد
+۲۲۵
+۱۹۱
+بافق
+ژاله
+آبریز
+صدد
+املاک
+مقاله‌
+بوانات
+پژو
+زمان‌ها
+کامیاران
+پگاه
+۲۰۲
+حرف‌های
+ترغیب
+حک
+مسطح
+دی‌وی‌دی
+جانبه
+سفیران
+غدد
+هستند؟
+مدرسه‌های
+۵۲،
+منبع‌دار
+چاله
+نائین
+مدير
+عکاسان
+آب‌خورده
+فیات
+خبرنامه
+مشهدی
+استرالیایی
+سیامک
+بگیر
+شایان
+درسته
+نامند
+ویرایشهای
+گل‌ها
+مایا
+گروه،
+آتشفشانی
+کرده‌است،
+نیمهٔ
+آزادشهر
+رانده
+علاقه‌ای
+ثریا
+متشکر
+ولت
+فرزانه
+صورت‌های
+دانشگاههای
+وز
+ویدئوی
+جنازه
+برتون
+جلوه‌های
+تغییرمسیرهای
+بیانیه‌ای
+دون
+نبوی
+یک‌بار
+رک
+حزب‌های
+مدارهای
+میگویم
+كنيم
+معلق
+تماشاگران
+نش
+نصیر
+۱۹۴
+رضاخان
+گردد،
+کنسول‌های
+قسمتهای
+شورشیان
+دقیق‌تر
+مداخله
+علاءالدین
+استنباط
+مصرفی
+باردار
+اهورامزدا
+ادبيات
+باهنر
+مقرر
+عزاداری
+كلمه
+خونین
+محدودی
+نمی‌دارد
+ذوق
+پرسش‌های
+بریم
+قشر
+۳۸،
+صالح‌آباد
+محسنی
+تخلص
+شکل‌های
+شوی
+رنگ‌ها
+توربین
+مگابایت
+فسفات
+واجد
+اهانت
+محفل
+برحسب
+گیگا
+گيرد
+۱۸۷۰
+صنفی
+تن‌تن
+برگردانده
+دایناسور
+لای
+می‌بینیم
+۰۴،
+فرمائید
+سیارات
+۵۱،
+تص
+سرودهای
+معترض
+ممكن
+متا
+می‌شویم
+ثلاث
+گفته‌های
+بی‌طرفانه
+هاپ
+نهان
+ادارات
+عجیبی
+جنایات
+دستورالعمل
+پارا
+نهادند
+ام،
+فتنه
+فواصل
+۱۸۵۰
+توریستی
+مرمر
+دیتابیس
+۴۲،
+کلیات
+۱۸۸۳
+لنین
+بلكه
+کاتوزیان
+میسیسیپی
+معاویه
+یوونتوس
+کشاورزی،
+هوافضا
+كوخرد
+فاریاب
+محيط
+نکنید،
+میترا
+رنگین
+آلپ
+آلومینیوم
+ملودی
+سیاستمداران
+گمر
+اسکان
+مختصری
+قشون
+جوادی
+رباتی
+۲۱۱
+جایز
+۲۷،
+محمودی
+كاربران
+یافته‌اند
+بگذریم
+محوری
+زمان‌های
+۲۲،
+انصراف
+میلا
+ساير
+۲۱۴
+تصریح
+۳۶،
+۲۸،
+آلباسته
+وظیفهٔ
+آذرشهر
+خدمه
+بارانی
+فیزیک‌دانان
+۱۸۸۴
+تماشای
+۱۳۱۱
+نويسنده
+علامرودشت
+افزاری
+گلشیری
+عملیات‌های
+داس
+ناخواسته
+هوتن
+واسه
+ثانیا
+لینه
+سنج
+اروپا،
+ایلیا
+بازمانده
+بشریت
+شناسی،
+۱۷۰۰
+کالیفرنیا،
+نکرده‌ام
+سیلیکات
+آزاده
+کامنت
+یونیکد
+آمدم
+احضار
+توده‌ای
+فرایندهای
+بیماری‌ها
+آخه
+تبلور
+۰۷،
+۲۰۷
+مونوبوک
+تصمیمات
+اختراعات
+جشنوارهٔ
+مشاهدات
+ریزشگاه‌ها
+۲۹،
+فیلادلفیا
+یزید
+سکولار
+خشایارشا
+سنتور
+محافظه
+کاپ
+نادرستی
+علی،
+محیط‌های
+منفرد
+اهتمام
+القاعده
+علاقهٔ
+لرزش
+عصبانی
+پسند
+لیل
+۲۲۶
+جدای
+جواهر
+ژولیوسی
+کوچک،
+شمیرانات
+بخوانند
+ربیع‌الثانی
+۵۰،
+۲۳۵
+توپخانه
+نیکلاس
+ویستا
+فردیناند
+۲۸۰
+تشییع
+نمیکند
+موسیقی،
+نیرومند
+۱۸۷۸
+غفاری
+بفتا
+هویدا
+صدیقی
+سلیمانی
+سياسي
+شهرضا
+جوانرود
+انتشاراتی
+شخصه
+۵۵،
+آسیاب‌های
+خوب،
+راههای
+والنشر
+حماسی
+عکسها
+۲۱۲
+۱۸۸۵
+تعریفی
+قاسمی
+مصادف
+مفرغ
+گشتاور
+۱۸۷۵
+شکل‌گیری
+طهماسب
+موجودیت
+ستاره‌ها
+آوردید
+سازه‌های
+۲۱۷
+ببریم
+ارسنجان
+بیدگل
+مگه
+عبادی
+فایل‌های
+۱۸۷۶
+تبریز،
+رهنما
+سپر
+قاره‌ای
+وو
+جعبه‌ای
+دانش‌نامه
+اجتماعي
+هیجان
+کارتر
+نرسید
+۳۳،
+کارم
+نمی‌شود،
+نسل‌کشی
+نمونه،
+صمد
+دریک
+میله
+پلاسما
+زاغ‌ده
+داروین
+۴۴،
+ویس
+قاچاق
+املای
+نامیدن
+گنجانده
+شادگان
+نی‌بید
+۲۲۲
+تسهیل
+هلن
+ناپدیدشدن
+خط‌ها
+ابلاغ
+شمع
+بازی،
+فندقاع
+جوهر
+پترزبورگ
+هخ
+سکو
+۴۱،
+یاسر
+۵۷،
+مستلزم
+آلبومی
+کلک
+ضخیم
+پاشا
+۲۳،
+۱۸۸۱
+دی‌ان‌ای
+حساب‌های
+غلامعلی
+خواندند
+معلمان
+همیلتون
+مداری
+مست
+تصویرها
+اندیشهٔ
+شدیداً
+دیواندره
+کنن
+بشوند
+نیامد
+مانگا
+۱۳۱۷
+چسب
+شجاعت
+مشتاق
+ایرا
+دانا
+بریتیش
+ویکی‌پدیاها
+مهم‌تر
+روبرت
+کافه
+ئی
+ارضی
+دست‌کم
+دندان‌پزشکی
+مهرآباد
+كننده
+رضوانشهر
+پراگ
+پال
+فرسایش
+درگاه‌ها
+راور
+میکروسکوپ
+فشارهای
+آرزومندم
+مصاحبه‌ای
+ویولن
+دریافت‌کنندگان
+نجیب
+سئول
diff --git a/perf/texts/hi-words.txt b/perf/texts/hi-words.txt
new file mode 100644
index 000000000..1dc18dcc1
--- /dev/null
+++ b/perf/texts/hi-words.txt
@@ -0,0 +1,10000 @@
+के
+में
+की
+है
+का
+और
+से
+को
+है।
+एक
+पर
+श्रेणी
+वार्ता
+भारत
+हैं
+भी
+यह
+शीर्षक
+पूर्व
+लिए
+गाँव
+ईसा
+उत्तराखण्ड
+किया
+ने
+इस
+संवत
+कि
+हिन्दी
+जो
+।
+जाता
+गया
+या
+जिले
+वर्ष
+जिला
+नहीं
+कर
+साँचा
+ही
+हैं।
+करने
+हो
+रूप
+था
+साथ
+द्वारा
+जन्म
+तहसील
+फ़िल्म
+होता
+तथा
+बाद
+विकिपीडिया
+आधार
+अन्य
+प्राचीन
+कुछ
+सदस्य
+अपने
+इसके
+प्रदेश
+तो
+एवं
+तक
+चित्र
+बाहरी
+राज्य
+जा
+प्रकार
+सरकार
+नाम
+दिया
+होती
+स्वागत
+कई
+वह
+बिहार
+करते
+सप्तर्षि
+जैसे
+थे
+समय
+अनुसार
+आदि
+वे
+सकते
+अधिक
+वाले
+किसी
+आधिकारिक
+सकता
+कड़ियाँ
+भारतीय
+उत्तर
+मण्डल
+हुए
+न
+जाती
+प्रखण्ड
+हुआ
+क्षेत्र
+लेख
+द
+बनी
+होने
+उसके
+करता
+इन
+अंग्रेज़ी
+संदर्भ
+थी
+था।
+शक
+कारण
+भाषा
+बहुत
+स्थित
+पहले
+उनके
+प्रसिद्ध
+सहायता
+जब
+दो
+अपनी
+कोई
+सबसे
+अलावा
+स्थान
+होते
+कम
+विश्व
+लिये
+ये
+जाने
+बारे
+लेकिन
+प्रयोग
+उन्होंने
+राष्ट्रीय
+वर्षों
+कहा
+पृष्ठ
+गए
+रहा
+आप
+देखें
+व
+एक्स्प्रेस
+तरह
+मे
+करना
+शामिल
+सभी
+प्रमुख
+आंध्र
+इसी
+अमेरिका
+प्राप्त
+करें
+अन्तर्गत
+इसे
+माना
+सितंबर
+उस
+५७
+इसका
+जानकारी
+नगर
+मुख्य
+हुई
+शिक्षा
+उन्हें
+संस्कृत
+कलियुग
+बीच
+गई
+विक्रमी
+रहे
+उपयोग
+मार्च
+पोर्टल
+काम
+वेबसाइट
+जनवरी
+कुमाऊँ
+उसे
+शहर
+जाते
+उनकी
+लोग
+जिसमें
+देश
+दी
+संघ
+थे।
+भाग
+लोगों
+जीवन
+१
+कार्य
+जी
+फिल्म
+विशेष
+बार
+ओर
+२
+इतिहास
+कभी
+दोनों
+अब
+निर्माण
+२००९
+पुरस्कार
+वाली
+शब्द
+पताका
+अधिकांश
+चिह्न
+विकास
+धर्म
+केवल
+लिया
+ए
+दक्षिण
+पुराने
+जुलाई
+यहाँ
+नया
+स्टेशन
+फिर
+लगभग
+संयुक्त
+अलग
+आन्ध्रप्रदेश
+गढ़वाल
+स्थल
+दिल्ली
+ई
+आरम्भ
+अपना
+जून
+विस्तृत
+यदि
+प्रान्त
+इसकी
+सूत्र
+शुरु
+मंदिर
+जालपृष्ठ
+जिसे
+घटनाएँ
+कृषि
+दौरान
+करती
+निधन
+दिन
+संगीत
+यहां
+तीन
+क्योंकि
+इसमें
+साहित्य
+ऑफ़
+मूल
+भूगोल
+॥
+पास
+पटना
+नए
+हालांकि
+सिंह
+प्रदर्शित
+प्रतिरूप
+अप्रैल
+बात
+विषय
+टेनिस
+२०१०
+प्रतियोगिता
+प्रचलित
+कहते
+विज्ञान
+विभिन्न
+अगस्त
+ऑफ
+पद्धति
+छत्तीसगढ़
+सन्
+जाना
+शुरू
+बना
+समूह
+अनेक
+थी।
+ता
+प्रामाणिक
+मध्य
+रही
+सूची
+संख्या
+व्यक्ति
+ऐसा
+गणना
+प्रति
+आज
+तब
+उनका
+क
+इलाहाबाद
+ऐसे
+मैं
+काल
+हम
+युद्ध
+गया।
+वाला
+श्री
+आदर्श
+स्थिति
+सी
+सकती
+दिसंबर
+प्रदान
+विक्रम
+विश्वविद्यालय
+रेलवे
+बड़े
+सामूहिक
+किया।
+किए
+राज्यक्षेत्र
+यातायात
+उन
+चार
+उपरोक्त
+दर्शाता
+बन
+अर्थ
+अलीगढ़
+दूसरे
+तौर
+गयी
+५८
+अन्तर
+उत्तरा
+राजा
+प्रभा
+क्या
+घटित
+मानकर
+विभाग
+कैलेंडर
+देने
+बनाने
+खेल
+प्रथम
+हिंदी
+इन्हें
+एकल
+उसकी
+एंड
+मसीह
+अथवा
+अमेरिकी
+जहां
+उदाहरण
+कलाकार
+निकाले
+आवश्यक
+७८
+महत्वपूर्ण
+पुरुष
+मई
+नदी
+जिसके
+प्रभाव
+आम
+जूलियन
+योगदान
+किये
+अधारित
+ले
+अधार
+इस्तेमाल
+सेवा
+३०७६
+जिसका
+३१०२
+पंचाग
+६६७६
+चर्चा
+भोजपुरी
+कैसे
+उर्दु
+कलेण्डर
+करके
+चाहिए
+स
+कला
+उपलब्ध
+जनसांख्यिकी
+साल
+काफी
+फर्रुखाबाद
+आगरा
+कंपनी
+३
+उच्च
+अक्तूबर
+आ
+मेरा
+स्तर
+नवंबर
+नीचे
+देता
+अध्ययन
+जारी
+कोड
+पहली
+प्रणाली
+अगर
+ओपन
+ध्यान
+उसका
+नामक
+बड़ी
+जल
+नैनीताल
+अक्सर
+अंग्रेजी
+सरकारी
+वर्तमान
+रंग
+जिससे
+मेल
+पुलिस
+रखा
+प्रत्येक
+हर
+बनाया
+ट्रेन
+सामान्य
+दुनिया
+भूमिका
+लिंक
+दे
+जबकि
+सन्देश
+शरीर
+पता
+भागलपुर
+विचार
+जहाँ
+लगा
+लेकर
+बड़ा
+वर्ग
+आगे
+छोटे
+तथ्य
+समाज
+पानी
+इससे
+उसने
+देशों
+महिला
+इसलिए
+देना
+पर्यटन
+एस
+परिणाम
+अल्मोड़ा
+सब
+स्थापना
+बाह्य
+स्थापित
+पौड़ी
+दल
+माध्यम
+आधारित
+पश्चिम
+प्रदर्शन
+सर्वश्रेष्ठ
+चीन
+शक्ति
+बाहर
+बी
+ऊपर
+बेगूसराय
+उत्पन्न
+हेतु
+डी
+आशीष
+अतिरिक्त
+समान
+वीं
+हिन्दू
+गये
+परिवर्तन
+आधुनिक
+लिखा
+कुमार
+देखा
+अंत
+मार्ग
+मानव
+रेल
+अक्टूबर
+आपको
+घर
+प्रश्न
+दूर
+कन्नौज
+भटनागर
+सामाजिक
+प्रकाशित
+अभिनेता
+देते
+कुल
+अभी
+जिस
+होना
+आई
+४
+पूरी
+संबंधित
+रहता
+ज्ञान
+ब्रिटिश
+कृपया
+हस्ताक्षर
+व्यक्तिगत
+बिना
+नई
+रोग
+१०
+दशक
+अधिकार
+परिवार
+शैली
+लेखक
+संस्करण
+जिनमें
+सेना
+संबंधी
+औरंगाबाद
+प्रक्रिया
+यात्रा
+२००८
+नये
+आवश्यकता
+ऐसी
+स्वयं
+होगा
+संबंध
+चिकित्सा
+मात्रा
+परियोजना
+प्रबंधक
+१५
+विकसित
+संदेशों
+होकर
+प्रकाश
+पहाड़ी
+पहला
+आकार
+सुधार
+जगह
+पन्ना
+सही
+मैथिली
+तैयार
+नवम्बर
+पिता
+मुक्त
+क्षेत्रों
+रचना
+१२
+२००७
+पूरा
+पी
+संस्थान
+५
+लोक
+१३
+चरित्र
+तुलना
+हुआ।
+लाल
+उत्पादन
+जनसंख्या
+रहते
+उसी
+इनके
+ा
+१४
+संदेश
+ज्यादा
+शताब्दी
+मृत्यु
+साधारण
+पाकिस्तान
+मास्टर्स
+दूसरी
+पुस्तक
+भगवान
+इनमें
+पूर्ण
+लाभ
+टीम
+बैंक
+अवधि
+भिन्न
+खिलाड़ी
+ली
+सदस्यों
+आने
+प्रयोक्ता
+कार्यक्रम
+सीमा
+समर्थन
+संस्कृति
+े
+अंतिम
+स्कूल
+बने
+विकि
+टी
+अ
+पाया
+नही
+र
+सदी
+फरवरी
+मुझे
+सन
+परिचय
+लेने
+मेरे
+पार्टी
+उत्तरी
+लिखने
+१८
+दिसम्बर
+राम
+भर
+विशिष्ट
+मी
+क्षमता
+प्रयास
+सहित
+पश्चिमी
+सिद्धांत
+दर्शन
+सभा
+किंतु
+वर्णन
+विधि
+श्रृंखला
+बजे
+संगठन
+गीत
+एम
+बेबल
+राजधानी
+प्रभावित
+पौडी
+ठीक
+सुझाव
+गति
+प्रबंधन
+व्यापार
+सामग्री
+ना
+एन
+दृष्टि
+दिया।
+पद
+ब्रजभाषा
+म
+सूचना
+शोध
+नामांकन
+अवधी
+लोकप्रिय
+आन्ध्र
+हाथ
+रहने
+विस्तार
+ऑस्ट्रेलिया
+वृद्धि
+फ़रवरी
+११
+जैसा
+आर
+कहानी
+व्यवस्था
+क्रिकेट
+बागेश्वर
+पृथ्वी
+चमोली
+गांव
+युग
+यौगिक
+कहीं
+पूर्वी
+२०
+सुरक्षा
+मुखपृष्ठ
+स्पष्ट
+१६
+मिलता
+देवी
+यही
+बुंदेली
+सामने
+प्रवेश
+यूरोप
+रखने
+दिए
+जॉन
+जिन्हें
+दूसरा
+पूरे
+स्थानीय
+आते
+नियंत्रण
+चीनी
+दिखाई
+प्रकाशन
+ऊर्जा
+प्राकृतिक
+की।
+जैन
+लगता
+बनाए
+अमरीकी
+कवि
+व्यापक
+दर
+वजह
+वहाँ
+परीक्षण
+लंदन
+प
+ी
+बदल
+जाए
+अदिलाबादु
+शासक
+खोज
+द्वितीय
+बस्तर
+मदद
+योजना
+ब्रिटेन
+प्रस्तुत
+जे
+धार्मिक
+आर्थिक
+सहायक
+लेखन
+शुरुआत
+मिल
+डॉ
+प्रौद्योगिकी
+शासन
+स्रोत
+रायगढ़
+वैज्ञानिक
+कमी
+आपके
+मिनट
+पत्र
+निर्वाचन
+रक्त
+ऑफिस
+गूगल
+संग्रह
+उद्योग
+राष्ट्र
+एशिया
+सांस्कृतिक
+पदार्थ
+इनका
+आपका
+मुंबई
+हिस्सा
+दृष्टिकोण
+उद्देश्य
+वी
+ह
+दूरी
+आता
+अनुवाद
+वो
+पीछे
+भूषण
+क्रिया
+स्वास्थ्य
+पैदा
+केंद्र
+२०११
+अच्छे
+पद्म
+शब्दों
+ऐतिहासिक
+गैर
+पिथोरागढ
+छोटी
+६
+सार्वजनिक
+कपूर
+प्रेम
+मुंगेर
+रहती
+चैनल
+समस्या
+कनाडा
+अंतर्गत
+देवनागरी
+राष्ट्रपति
+जिसने
+बैंड
+साम्राज्य
+कॉलेज
+मगही
+प्रयुक्त
+पुत्र
+अनुसंधान
+पहचान
+निर्मित
+किमी
+बंद
+प्रतिशत
+लगे
+अंतर्राष्ट्रीय
+ताकि
+भूमि
+मानक
+इंग्लैंड
+सके
+प्रारंभिक
+सन्दर्भ
+थीं
+अंगिका
+दिशा
+जर्मनी
+१९
+संकेत
+बच्चों
+द्वीप
+समाचार
+अफ्रीका
+घोषणा
+रह
+बंगाल
+भाषाओं
+घंटे
+हाल
+राजस्थान
+वहां
+आया
+उपन्यास
+कानून
+दिनों
+अभिनेत्री
+खिलाफ
+सदर
+अनुमति
+हवाई
+टीवी
+समाप्त
+मीडिया
+उपचार
+हमारे
+जनता
+नियम
+संक्षेप
+मन
+मिलियन
+चौपाल
+उपकरण
+राज
+भीतर
+चेन्नई
+२८
+कृष्ण
+क्लिक
+३०
+कविता
+कथा
+सूर्य
+प्रेस
+वीडियो
+स्वतंत्रता
+वन
+राजनीतिक
+आमतौर
+देती
+दृश्य
+न्यू
+योग्य
+लागू
+मिला
+बताया
+मैच
+जिसकी
+सा
+मीटर
+नेटवर्क
+रोचक
+भोजन
+हूँ
+मौजूद
+धीरे
+१७
+संभव
+माता
+नृत्य
+७
+महत्व
+परन्तु
+आशा
+डॉलर
+शायद
+आयोजित
+सम्मान
+युगल
+कांग्रेस
+सफल
+उर्दू
+उनमें
+वापस
+चाहिए।
+दें
+मनुष्य
+लाख
+महान
+निजी
+उल्लेख
+जैसी
+इनकी
+व्यवहार
+पन्ने
+नीति
+जाति
+एल
+पोस्टर
+विशाल
+बल्कि
+संचालित
+देखने
+विवाह
+अच्छा
+ख़ान
+२६
+इ
+कृष्णा
+वंश
+जापान
+केन्द्र
+मेरी
+तमिल
+देख
+विजेता
+वेब
+शिव
+सिर्फ
+न्यूयॉर्क
+भाई
+यूरोपीय
+राजीव
+प्रयोगस्थल
+उत्पाद
+मंच
+पांच
+०५
+पंजाब
+०४
+राजमार्ग
+मॉडल
+कंप्यूटर
+स्वीकार
+अंतर
+कार्बनिक
+सक्रिय
+परंतु
+लखीसराय
+किलोमीटर
+यमकेश्वर
+चला
+आलेख
+पड़ता
+उसमें
+ज्ञानसन्दूक
+आपने
+हमें
+मान
+इंजन
+तहत
+पत्रिका
+अवस्था
+९
+चम्पावत
+ं
+सहयोग
+मौलिक
+मामले
+अच्छी
+तिथि
+आरंभ
+स्वतंत्र
+बल
+बाजार
+८
+प्रारंभ
+मूल्य
+सरल
+वास्तव
+यू
+उससे
+तुम
+मैंने
+पुनः
+सागर
+पक्ष
+०६
+छोड़
+खाना
+अनुभव
+टू
+तरफ
+बस
+विजय
+महाराष्ट्र
+समुद्र
+उचित
+रेडियो
+चल
+हटाने
+खुद
+समीक्षाएँ
+जीव
+तेल
+दिल
+उम्र
+जर्मन
+ग्रंथ
+रूस
+संपर्क
+बौक्स
+रखें
+गंगा
+एल्बम
+राय
+पाठ
+हासिल
+निश्चित
+सीमित
+सात
+प्रांत
+गई।
+नेपाल
+दक्षिणी
+काव्य
+निर्णय
+छोटा
+२५
+डिजाइन
+रात
+हों
+लगाया
+वास्तविक
+पूछे
+ज्ञात
+प्रकृति
+कार
+गए।
+निर्वाचित
+तरीके
+त
+ज
+चुनाव
+किन्तु
+बढ़
+२१
+हो।
+जीत
+विपरीत
+दस
+वर्मन
+औसत
+इंडिया
+सम्मानित
+२२
+नाटक
+अधिनियम
+वस्तु
+संरचना
+मत
+सर्वाधिक
+लेखों
+विश्वास
+मास
+संकिपा
+वायु
+शीघ्र
+घटना
+निम्न
+विरोध
+सप्ताह
+स्वरूप
+प्रवेशद्वार
+सितम्बर
+गुरु
+सॉफ्टवेयर
+निर्धारित
+विद्युत
+रक्षा
+पूर्णिमा
+पड़ा
+बावजूद
+बेहतर
+वर्ल्ड
+चुका
+भारी
+मगध
+समुदाय
+क्यों
+ऑस्ट्रेलियाई
+जनगणना
+लीग
+अंक
+मिलती
+भागों
+बाल
+भेज
+कप
+कोरिया
+कर्नाटक
+मात्र
+हुई।
+अत्यंत
+तत्व
+महाभारत
+ओ
+अरब
+पूजा
+निर्माता
+रोमन
+विदेशी
+अल
+पर्वत
+पिछले
+इनसे
+पार्क
+स्थानों
+जिन
+धारा
+चुके
+मिली
+जाकर
+बदलने
+स्वामी
+सम्मेलन
+२३
+बनाये
+अल्मोडा
+शो
+जंक्शन
+मन्दिर
+गलत
+सफलता
+लिपि
+पाए
+योग
+निर्भर
+सिस्टम
+प्रसाद
+गांधी
+प्रचार
+फ्रांस
+वर्मा
+जिन्होंने
+रहें
+बौद्ध
+बच्चे
+आंदोलन
+एच
+तंत्र
+मोबाइल
+कोशिश
+अध्यक्ष
+गैस
+प्यार
+सारे
+ल
+लक्ष्य
+अवश्य
+लेते
+आसपास
+चरण
+पर्याप्त
+आयु
+शर्मा
+कार्बन
+सुरक्षित
+कोलकाता
+शीर्ष
+२७
+मै
+समिति
+धन
+विवरण
+सुविधा
+खान
+आती
+जिनके
+यद्यपि
+मामलों
+प्रशिक्षण
+सिटी
+कैंसर
+पात्र
+इतना
+रिपोर्ट
+नेतृत्व
+महिलाओं
+फल
+महीने
+सड़क
+देव
+मान्यता
+क्लब
+अनंतपुर
+क्रम
+य
+बजाय
+साँचे
+उप
+२४
+विश्लेषण
+आनन्द
+यूनानी
+चाहते
+राज्यों
+फाइनल
+अवार्ड
+जुड़े
+अत्यधिक
+तकनीक
+अज्ञात
+निकट
+सेंट
+चलता
+रेखा
+निर्देशक
+इंडियन
+मानते
+देवता
+जांच
+हे
+पत्नी
+इंटरनेट
+केरल
+जोखिम
+रिकॉर्ड
+बदलाव
+डिग्री
+प्रतीक
+जाएगा
+अतः
+पालन
+खंड
+विष्णु
+भौतिक
+जिनका
+अकादमी
+होगा।
+गुण
+वित्तीय
+क्षेत्रफल
+कर्नूलु
+करें।
+भाव
+तापमान
+०७
+अनुमान
+डे
+अमरीका
+रासायनिक
+च
+ग
+अभिनय
+पत्थर
+खाता
+किस
+गणराज्य
+टेस्ट
+चोर
+इत्यादि
+शुद्ध
+होगी
+भिकियासैण
+संघर्ष
+अंतरराष्ट्रीय
+लगातार
+माँ
+उल्लेखनीय
+रखते
+लक्षण
+जेम्स
+ग्रह
+प्राय
+वही
+औद्योगिक
+संक्षिप्त
+२००६
+विमान
+टिप्पणी
+नागरिक
+ध्वनि
+याद
+संचार
+बराबर
+प्रधान
+अमेरिकन
+पारंपरिक
+युक्त
+अत
+पुरी
+प्रतिक्रिया
+शाह
+चक्र
+अवसर
+हमेशा
+शारीरिक
+हंडिया
+आबादी
+तट
+लाइन
+विकल्प
+अंग
+लोकसभा
+खाद्य
+पर्यावरण
+संसार
+विवाद
+बनने
+करीब
+व्यक्तियों
+०
+वैदिक
+बिक्री
+ब
+निम्नलिखित
+कोशिका
+पार
+परमाणु
+भवन
+समझ
+नष्ट
+स्वर
+दुर्ग
+जितना
+प्रकट
+फॉर
+विमानक्षेत्र
+रख
+रुप
+शहरों
+तकनीकी
+लखनऊ
+मुद्रा
+हिस्से
+झील
+आयोजन
+इकाई
+मील
+समस्त
+संरक्षण
+अंदर
+संस्था
+परंपरा
+सतह
+कार्यों
+विद्यालय
+संसद
+अभियान
+सिद्ध
+मुख्यालय
+प्रस्ताव
+सीधे
+सर्वोच्च
+डालकर
+वाहन
+गुजरात
+उपयुक्त
+राशि
+बोली
+सक्षम
+अधिकतर
+नेशनल
+प्राथमिक
+मौत
+इसने
+गणित
+अली
+व्यवसाय
+हवा
+मिट्टी
+अगले
+फिल्मों
+चले
+डेविड
+मिलते
+बनाई
+महल
+आक्रमण
+रे
+राजनीति
+मंत्री
+गंभीर
+शाखा
+अम्ल
+हटा
+तटस्थ
+भविष्य
+ईश्वर
+आए
+वि
+दावा
+प्रसारण
+जीवित
+कड़ी
+रखें।
+लिमिटेड
+अन्दर
+क्रांति
+लिखे
+मैदान
+धातु
+एफ
+सम्बन्ध
+विलियम
+हृदय
+संभावना
+वातावरण
+न्यायालय
+लगाने
+सैन्य
+परिवहन
+परिषद
+चारों
+पवित्र
+योगदानकर्ताओ
+गुणवत्ता
+खगड़िया
+शेष
+करे
+ला
+युवा
+नियमित
+ऑन
+सर
+पसंद
+दबाव
+ईरान
+लागत
+०९
+०८
+२९
+अधिकारी
+उनसे
+कहना
+बोर्ड
+ग्रहण
+अशोक
+स्टार
+जान
+दिखाया
+ग्राम
+स्पेन
+नीतियाँ
+सभ्य
+०००
+समारोह
+संविधान
+इटली
+आठ
+संग्रहालय
+तर्क
+दूतावास
+पाने
+लिया।
+पाँच
+थलीसैंण
+लगी
+जन
+ताप
+परिणामस्वरूप
+लॉग
+लिखी
+रॉक
+कार्ड
+प्रेरित
+आगंतुकों
+फूल
+तेलगू
+लेता
+मिले
+रोगी
+आक्षेप
+जरूरत
+गठन
+व्यक्त
+भुगतान
+मौसम
+मीडियाविकि
+अन्तर्राष्ट्रीय
+पदार्थों
+पूर्वाग्रह
+रहे।
+शादी
+पुरा
+विषयों
+बिलियन
+ढंग
+आदेश
+लंबे
+काउंटी
+धन्यवाद
+मुस्लिम
+विरोधी
+वेल्स
+लिखें।
+पुरानी
+कांडा
+रानी
+विभाजित
+मिलकर
+तारा
+वैसे
+ईसाई
+पू
+शिकार
+ज्ञानसंदूक
+नेता
+शास्त्र
+कौन
+राजवंश
+ब्लैक
+अस्तित्व
+धारी
+प्र
+०३
+तेजी
+रायपुर
+संवाद
+किनारे
+टाइम्स
+भार
+सिर
+उत्तरप्रदेश
+छह
+आलोचना
+दिये
+गुप्त
+गेम
+नियंत्रित
+पुराण
+उद्यान
+डालें।
+हिंदू
+डीवीडी
+परीक्षा
+वालों
+घरेलू
+वस्तुओं
+व्याख्या
+पौराणिक
+अर्थात
+फूलपुर
+करोड़
+दिवस
+लघु
+जिसमे
+पिथौरागढ
+विज्ञापन
+पेश
+चर्च
+घोषित
+कंपनियों
+पशु
+पाएँ
+दर्द
+चलते
+समाधान
+माइकल
+सामना
+पूछें
+लड़ाई
+जोड़ें।
+संपादित
+जनरल
+विविध
+मिश्र
+आग
+भावना
+टिल्ड
+कैलंडर
+हत्या
+ग्रेगोरी
+प्रशासन
+रिलीज़
+खास
+मध्यम
+ज्यादातर
+अरबी
+रानीखेत
+देखते
+पाई
+आसानी
+अंश
+कश्मीर
+नवागंतुकों
+प्रभावी
+लिख
+किताब
+जीन
+इंडियाना
+चूंकि
+सत्य
+गंगोलीहाट
+नामांकित
+कोशिकाओं
+कार्यालय
+छात्र
+मस्तिष्क
+डेटा
+अनुनाद
+मंडल
+चुकी
+नारायण
+कर्म
+संपूर्ण
+प्रतिनिधित्व
+पहुंचती
+तेज
+अपेक्षा
+जाएगा।
+व्यंजन
+आत्मा
+वैश्विक
+मांग
+सेट
+इन्होंने
+सम्पूर्ण
+बदलें
+लग
+एशियाई
+रोड
+ऑनलाइन
+इस्लाम
+दास
+संत
+पक्षी
+बीबीसी
+व्यावसायिक
+सीज़न
+फुट
+जानते
+संक्रमण
+विचारों
+चाहता
+मतलब
+विरुद्ध
+रसायन
+निवेश
+वर्षा
+प्रमंडल
+संस्कार
+केन्द्रीय
+अंतरिक्ष
+ध्वज
+विशेषता
+बाकी
+थीं।
+यूनिवर्सिटी
+शंकर
+दैनिक
+आचार्य
+सं
+अनुरोध
+गायक
+मानसिक
+जमा
+हाउस
+मंत्रालय
+पहुंच
+जॉर्ज
+उपस्थित
+मार
+प्रधानमंत्री
+अंततः
+घनत्व
+थराली
+दूध
+सेवाओं
+वर्णित
+नियमों
+यूनाइटेड
+साथी
+विभाजन
+आपकी
+चौबटाखाल
+सम्मिलित
+प्रवाह
+गोल
+हुए।
+बिलासपुर
+कह
+जलवायु
+ब्राह्मण
+समर्पित
+निवास
+फोन
+प्रमाण
+पैमाने
+बिजली
+रोहित
+शांति
+अति
+उत्पत्ति
+तीसरे
+आनंद
+हमारी
+एकमात्र
+नुकसान
+मिलने
+पे
+सौ
+घटनाओं
+मां
+प्रायः
+भौतिकी
+कठिन
+माने
+घाटी
+अधीन
+स्थिर
+लेना
+उपयोगी
+रखना
+छूटती
+द्वार
+वेद
+चैम्पियनशिप
+बिंदु
+जुड़ा
+कल्पना
+आये
+संपादन
+तारे
+दें।
+परिभाषित
+उ
+सिद्धार्थ
+जापानी
+ऊंचाई
+भौगोलिक
+समुद्री
+आदमी
+उपकरणों
+स्त्री
+वाक्य
+निर्देश
+मशीन
+०२
+सत्र
+फुटबॉल
+घाट
+उपग्रह
+पंथ
+बहुधा
+हाइड्रोजन
+लंबी
+श
+सुंदर
+दौर
+रखता
+फ़ाइल
+मोहन
+देकर
+काला
+नंबर
+उपस्थिति
+दवा
+जीवनी
+आंतरिक
+परिवर्तित
+ज्ञानकोष
+वहीं
+आय
+समझा
+निगम
+वृक्ष
+पॉल
+बुद्ध
+बाज़ार
+मराठी
+रूसी
+जय
+ग्रैंड
+संचालन
+तत्वों
+व्यक्तित्व
+कीया
+३१
+कारणों
+बनाना
+अपराध
+फिल्में
+चक
+व्यास
+चाहे
+छोड़कर
+नमस्कार
+टेलीविजन
+डा
+वितरण
+एक्स
+पुराना
+रामायण
+बेरीनाग
+ग्रामीण
+सेंटर
+लाइसेंस
+मित्र
+छात्रों
+अध्याय
+शेयर
+अभाव
+मानना
+विद्वानों
+जनजातियां
+वैकल्पिक
+तुर्की
+जैव
+पश्चात
+नहीं।
+डिजिटल
+तारीख़
+समीक्षा
+हजार
+प्रिय
+इतनी
+अर्जुन
+शराब
+स्मृति
+जीता
+उच्चारण
+श्रीलंका
+बीजापुर
+निकल
+स्वीडन
+सत्ता
+संपत्ति
+गर्म
+बीमारी
+अर्थात्
+५०
+सम्राट
+व्रत
+मिश्रण
+वार्षिक
+प्रत्यक्ष
+अंकित
+रॉबर्ट
+समूहों
+आपूर्ति
+इंजीनियरिंग
+कैलिफोर्निया
+उनको
+गेंद
+इच्छा
+रन
+ऋषि
+समस्याओं
+आन्दोलन
+अपेक्षाकृत
+रोम
+चाहिये
+चलने
+गतिविधियों
+गाने
+विम्बलडन
+हैरी
+एण्ड
+इंच
+सेवाएं
+वेस्ट
+वें
+जाये
+पहुँच
+हूं
+श्रेष्ठ
+रहा।
+हार
+अस्पताल
+निरंतर
+नियुक्त
+तारों
+ख
+केंद्रीय
+वर्तनी
+धारण
+दान
+वाराणसी
+स्टूडियो
+रोगियों
+कुकर्म
+साधन
+जटिल
+अक्षर
+देंगे
+स्कोर
+उत्पादों
+प्रोटीन
+अनिवार्य
+२००१
+कायमगंज
+सौर
+सरगुजा
+साबित
+ऊँचाई
+लीला
+सैनिक
+स्टेडियम
+रायगढ
+पर्व
+जयपुर
+व्याकरण
+रावत
+इसलिये
+करेगा
+तीव्र
+प्रकाशक
+कृतियाँ
+प्रसार
+नोबेल
+सभ्यता
+परिसर
+अफ़्रीका
+राजनैतिक
+इलाज
+साहित्यिक
+सतपुली
+लिखित
+फ्रेंच
+देखे
+ऋण
+अकबर
+सोवियत
+हमला
+प्रोग्राम
+मिस्र
+डाला
+छत्तीसगढ
+आयोग
+पुरुषों
+रस
+सुनिश्चित
+पेरिस
+साहित्यकार
+परिभाषा
+डाटा
+अर्थव्यवस्था
+महाराज
+ओम
+सह
+पेज
+जिनकी
+वर्ण
+दर्ज
+भारती
+तभी
+तय
+एसोसिएशन
+अनुपात
+झारखंड
+जोड़ा
+पुन
+छत्तीसगढ़ी
+यानि
+लकड़ी
+त्वचा
+अधिकतम
+कोरबा
+देखकर
+डाल
+पुरालेख
+कोइल
+बढ़ती
+सफेद
+प्रतीत
+कानूनी
+चयन
+बनता
+हाथों
+जल्दी
+चार्ल्स
+ग्रन्थ
+रोक
+कारक
+खाने
+अभ्यास
+कैरियर
+वर्गीकरण
+सर्वेक्षण
+नारायणपुर
+मिश्रित
+ें
+तमिलनाडु
+प्राप्ति
+आकर्षित
+भेजा
+बनाकर
+संग्राम
+किले
+अड्डा
+कहलाता
+महसूस
+मार्क
+माल
+वजन
+फ़्रेंच
+ठोस
+उपयोगकर्ता
+चम्पा
+सलाह
+भेद
+काफ़ी
+लोगो
+खाते
+निर्देशन
+स्वर्ण
+बनाते
+नोकिया
+मूर्ति
+हद
+रोकने
+समाप्ति
+अकाउंट
+कार्यक्रमों
+ग्रीक
+संधि
+लंबाई
+निवासी
+दौरे
+चाहें
+क्षेत्रीय
+स्थायी
+किंग
+न्याय
+मोटर
+संभवतः
+बनाता
+पेड़
+तल
+पति
+वां
+कराया
+शुरूआत
+प्रारूप
+काले
+कांकेर
+रखे
+पौधों
+खेलों
+००
+काशी
+मस्जिद
+हरा
+आकर्षण
+नयी
+रखी
+मजबूत
+कडप
+आजकल
+टंकण
+साक्षात्कार
+तीसरी
+खेती
+महासागर
+लाया
+जोड़
+सामान्यतः
+सम्बंधित
+सुन्दर
+रचित
+जांजगीर
+पृष्ठों
+दीवार
+उन्होने
+विद्या
+लाने
+पड़ती
+संयोजन
+तीसरा
+पड़
+रोगों
+संसाधन
+भाषाएँ
+मानचित्र
+जमीन
+देहरादून
+मुगल
+कोर्ट
+कवर्धा
+धमतरी
+जशपुर
+पौधे
+कदम
+आकर
+बढ़ा
+अधिकारियों
+आरोप
+मिलाकर
+बढ़ाने
+प्रशासनिक
+हमले
+टाइम
+प्रेरणा
+उड़ान
+शक्तिशाली
+पीपी
+महासमुन्द
+विधानसभा
+फीट
+प्रगति
+स्नातक
+सूक्ष्म
+जवाब
+कम्प्यूटर
+अप
+छवि
+फ़िल्मों
+भ
+शुल्क
+विभूतियाँ
+कलाकारों
+संकट
+संभावित
+दिशानिर्देश
+जोर
+विधान
+आहार
+गोठ
+उपाधि
+राजनांदगांव
+जम्मू
+सतनाम
+कर्णप्रयाग
+थोड़ा
+बाबा
+साइट
+तथापि
+दन्तेवाड़ा
+यानी
+अमर
+मार्टिन
+तुरंत
+जिले।
+लाइव
+पुनःप्राप्त
+निर्धारण
+तत्कालीन
+कक्षा
+सारी
+प्रजातियों
+गये।
+करो
+मूल्यांकन
+द्वाराहाट
+राजशाही
+घई
+होगी।
+गैरसैण
+हॉल
+बिल
+ऐ
+रूपों
+मंगल
+जानी
+चित्रण
+नीतियां
+शिक्षण
+अवधारणा
+चेक
+किला
+तीनों
+मारे
+इमारत
+आवासीय
+किंगडम
+राजीवमास
+चुना
+आँकड़े
+फलस्वरूप
+करेंगे
+ज्योतिष
+यंत्र
+ग्राहक
+चित्रों
+नौ
+सल्ट
+उम्मीदवार
+कोश्याँकुटोली
+बीज
+उत्कृष्ट
+०१
+कम्पनी
+महात्मा
+खर्च
+केंद्रित
+सिन्हा
+हाई
+प्रबंधकों
+मुश्किल
+नर
+गाँधी
+बनाएं
+करनी
+हूँ।
+स्टेट
+प्
+दार्शनिक
+निकाल
+मनोरंजन
+पुस्तकालय
+सोचते
+जेल
+हिमालय
+पा
+जहाज
+तरल
+यूनिकोड
+सैन
+हास्य
+पैर
+दि
+दी।
+खराब
+ख़ुदा
+कृति
+पुष्टि
+हल्द्वानी
+असम
+अर्थशास्त्र
+सेवन
+ग्रंथों
+कड़ियां
+बदले
+पुस्तकों
+हेनरी
+रिचर्ड
+परम
+सके।
+पृ
+रहना
+हल
+सर्वप्रथम
+सामान
+काली
+चेतावनी
+मनोविज्ञान
+बॉक्स
+छोड़ने
+संगठनों
+तारामंडल
+हैदराबाद
+छिबरामऊ
+मुख्यतः
+टैग
+४०
+यहूदी
+विद्रोह
+दर्शकों
+ग्रुप
+जोशी
+डीडीहाट
+सेन
+गरुङ
+कीमत
+पीटर
+कृत्रिम
+विपणन
+प्राण
+आस
+बुनियादी
+वीर
+जल्द
+ऊपरी
+टिप्पणियाँ
+नज़र
+पहुंचा
+लेखकों
+ईंधन
+गुणों
+२००४
+स्ट्रीट
+बचपन
+लैटिन
+मलयालम
+हिमाचल
+सरस्वती
+स्वामित्व
+जंगल
+भनोली
+भक्ति
+श्रीकृष्ण
+नवीन
+मैन
+पीढ़ी
+शहरी
+लव
+अररिया
+अनुबंध
+विश्वभर
+स्मारक
+पुर्णीमा
+देवताओं
+पढ़ें
+प्रसारित
+परिस्थितियों
+रास्ते
+टाटा
+वा
+तरीका
+विषाणु
+अनुप्रयोग
+ईरानी
+यात्री
+संशोधन
+क्रमांक
+पंडित
+ते
+माह
+मुक्ति
+गहराई
+सुबह
+यहीं
+नाथ
+संबद्ध
+उत्तम
+प्रजाति
+मापन
+गद्य
+टीका
+वित्त
+विख्यात
+अवतार
+उपनिषद
+दीया
+मुहम्मद
+राजाओं
+फैसला
+परंपरागत
+जर्नल
+व्यापारिक
+होंगे
+एयर
+चौखुटिया
+मथुरा
+लगते
+उसको
+तनाव
+सिंगापुर
+उत्सव
+पुणे
+अभिव्यक्ति
+बढ़ावा
+इसको
+बच्चन
+द्रव
+अनुरूप
+एट
+मेट्रो
+उत्सर्जन
+एलबम
+हरियाणा
+चलती
+वाणिज्यिक
+डॉक्टर
+चली
+मानी
+लगा।
+लॉस
+सैनिकों
+सवाल
+२००५
+आरंभिक
+निदान
+अतरौली
+कराने
+मालिक
+देर
+तीर्थ
+विदेश
+यथा
+प्रबंध
+संपादक
+जैविक
+दोस्त
+मि
+अनुकूल
+संस्थापक
+इंटरनेशनल
+स्लैम
+सकारात्मक
+टाइप
+पुस्तकें
+रा
+मियामी
+लगे।
+ड
+घटक
+निदेशक
+इतने
+प्रतिनिधि
+मितुल
+अंग्रेजों
+दोनो
+बांग्लादेश
+वनस्पति
+बढ़ने
+बंदरगाह
+आसान
+सटीक
+मनाया
+भू
+समकालीन
+पाठक
+दोष
+औपचारिक
+डिस्क
+बेटी
+संदर्भित
+निभाई
+राव
+सूरज
+मगर
+चलचित्र
+मछली
+देखी
+जगत
+ज़्यादा
+सर्वर
+लम्बाई
+ग्रेट
+कर्मचारियों
+पंजाबी
+अगला
+शाही
+दर्जा
+चिकित्सक
+विकार
+फैला
+शुक्ल
+प्रजनन
+हां
+सदा
+अग्रणी
+नायक
+गृह
+धन्यवाद।
+जालस्थल
+आवाज
+बनाम
+कपकोट
+संघीय
+बिग
+गलती
+विविधता
+नो
+लगती
+पेट
+रिलीज
+विद्वान
+अन्तिम
+कॉपीराइट
+नमक
+अधिकारों
+प्रणालियों
+युकेश
+आर्ट
+रॉयल
+बालक
+पश्चात्
+हटाया
+पर्यटक
+आर्य
+प्रीमियर
+शब्दावली
+परत
+सिद्धांतों
+हमारा
+अकार्बनिक
+चोट
+कौशल
+प्रारम्भ
+विकेट
+गुना
+ब्रह्म
+आयरलैंड
+पेशेवर
+इस्पात
+ठाकुर
+अग्नि
+कोश
+रुचि
+उपनाम
+दत्त
+उम्मीद
+पशुओं
+श्रेय
+मुम्बई
+निकाला
+सिख
+पदक
+कवियों
+इसीलिए
+मार्शल
+बॉलीवुड
+खन्ना
+प्रवृत्ति
+यौन
+रचनाओं
+उड़ीसा
+तेलुगू
+आश्रम
+अस्पष्ट
+माइक्रोसॉफ्ट
+महत्त्वपूर्ण
+चयनित
+शास्त्रीय
+कर्मचारी
+जैक
+खो
+विशेषकर
+शब्दकोष
+स्क्रीन
+प्रतिमा
+बर्फ
+फारसी
+महाराजा
+ब्लू
+शून्य
+जरूरी
+आनेवालों
+दौरा
+प्रतिभा
+सच
+मौजूदा
+क्षति
+स्थलों
+खून
+फ़िल्में
+प्रशंसा
+होटल
+सेल
+सालों
+थ
+दुर्गा
+हाँ
+स्मिथ
+बुक
+नोट
+रचयिता
+शिखर
+नेहरू
+ब्रांड
+सुख
+समझने
+मुंह
+महाविद्यालय
+ईस्ट
+शृंखला
+बचाने
+आध्यात्मिक
+पुल
+त्याग
+आविष्कार
+हजारों
+कहता
+जाय
+प्रक्रियाओं
+विलय
+दूसरों
+जाए।
+२०००
+वापसी
+आकाश
+थॉमस
+इलेक्ट्रॉनिक
+कडियाँ
+संगीतकार
+परस्पर
+मुख्यमंत्री
+उपभोक्ता
+प्राणी
+होनी
+आउट
+स्व
+उपनिषदों
+वक्त
+कक्ष
+यांत्रिक
+आंशिक
+बांग्ला
+संकोच
+शनि
+ट
+हिन्द
+पट्टी
+लंबा
+कन्या
+जीवों
+नैतिक
+किशोर
+फ्रांसीसी
+वस्त्र
+शिकागो
+नदियों
+संस्थाओं
+ो
+गतिविधि
+कठोर
+सोने
+कंपनियां
+बेटे
+प्रतिरोध
+दवाओं
+न्यूनतम
+खैर
+गरीब
+मेला
+निकटतम
+स्थानांतरित
+लौट
+विटामिन
+जोड़ने
+ब्रायन
+यादव
+सहारा
+अफ्रीकी
+सिनेमा
+रचनात्मक
+नामों
+यज्ञ
+स्थितियों
+तृतीय
+हुये
+रिंग
+पोषण
+कहने
+उपाय
+विशेषज्ञ
+चार्ट
+क्लासिक
+मानवीय
+कार्रवाई
+एक्सप्रेस
+निर्देशित
+सम्बन्धित
+ग्राहकों
+चलाने
+अड्डे
+चेतना
+देखभाल
+रंगों
+विकी
+कल
+संबंधों
+सम्पर्क
+निष्कर्ष
+तंत्रिका
+वैज्ञानिकों
+टॉम
+प्रयत्न
+२००३
+पाठ्यक्रम
+चिंता
+३५
+श्रम
+बहन
+काल्पनिक
+डब्ल्यू
+कपड़े
+डबल्यू
+जातियों
+खाड़ी
+गीता
+हाथी
+डिज़ाइन
+एकीकृत
+कन्नड़
+खतरा
+प्रस्तावित
+खरीद
+अन्त
+कार्यरत
+ग्रीन
+विकिरण
+असफल
+हानि
+लोहाघाट
+कानपुर
+खिलाड़ियों
+छ
+सूचित
+अयोध्या
+स्टॉक
+चन्द्र
+गवर्नर
+लिंक्स
+फ़ारसी
+खनिज
+मंदिरों
+गिरावट
+पोखरी
+सारा
+आवाज़
+वायरस
+विलियम्स
+राधा
+सेंट्रल
+सहमत
+बातें
+रामनगर
+लिंग
+श्वेत
+लक्षणों
+दर्शनीय
+बाराकोट
+ऐंड
+सन्‌
+रास्ता
+वसा
+शती
+बदला
+उन्नत
+हिन्दुस्तान
+३६
+पृष्ठभूमि
+हार्ट
+सहज
+गिटार
+इतालवी
+पर्यटकों
+हरे
+खुले
+वर
+व्युत्पन्न
+जाँच
+धारणा
+मुख
+होली
+खड़े
+प्रतिष्ठित
+पड़ा।
+बचने
+निवासियों
+बरो
+लेती
+पीठ
+पाकिस्तानी
+रामचरितमानस
+आपस
+समझौते
+महीनों
+कर्ण
+हिस्ट्री
+सो
+पोस्ट
+पंक्ति
+बहु
+संशोधित
+कोलंबिया
+बचाव
+रिकॉर्डिंग
+थोड़ी
+चुने
+चौधरी
+अंकों
+शाम
+बातचीत
+ओलम्पिक
+गर्मी
+फ्लोरिडा
+गोली
+लाइफ
+लम्बी
+बम
+चावल
+बातों
+वर्गों
+आवास
+मिशन
+सफ़ेद
+४५
+दशा
+अपलोड
+मेडिकल
+जानने
+कार्यकारी
+सकतें
+समीप
+संयंत्र
+नि
+आवेदन
+मांस
+गहरा
+तरीकों
+छः
+कल्याण
+लगने
+हुसैन
+औ
+संजय
+जंगली
+केन
+सुपर
+सबूत
+साफ
+क्रमश
+लॉर्ड
+समझौता
+नाडु
+अदालत
+आगमन
+प्रथा
+डालने
+औषधि
+करवाया
+जिम्मेदार
+यान
+पन्नों
+महावीर
+सकें
+परम्परा
+मेक्सिको
+गोल्डन
+गईं
+टन
+एकदिवसीय
+आदि।
+ऑल
+१००
+प्रदूषण
+अणु
+चोपड़ा
+भा
+संरक्षित
+प्रभावशाली
+पुचः
+जुड़ी
+प्रोत्साहित
+तल्ला
+साधना
+न्यूटन
+लोकप्रियता
+भरा
+प्रार्थना
+बंगाली
+द्रव्यमान
+व्यावहारिक
+ट्रैक
+सावधान
+बैठक
+तुम्हारे
+पॉटर
+रथ
+प्रोग्रामिंग
+कही
+कमल
+मशहूर
+नजर
+धरती
+स्वाभाविक
+चेहरे
+सकता।
+शिशु
+कोण
+पॉप
+मन्त्र
+५१
+निवेदन
+अकेले
+आवृत्ति
+३२
+उठा
+कवर
+गरम
+शैक्षिक
+वास्तुकला
+पाते
+खूबसूरत
+एसिड
+होता।
+जायेगा
+पड़े
+सीजन
+नीला
+योग्यता
+वैध
+ग्लोबल
+पथ
+बीमा
+हिस्सों
+माप
+मैने
+बारह
+उल्लंघन
+जानवरों
+प्रवासी
+साहब
+एजेंसी
+हिट
+सुविधाओं
+सोच
+रवि
+गीतों
+पेन
+गुजराती
+अगली
+दर्शाया
+पतन
+चित्रित
+आकृति
+मैसूर
+बुद्धि
+मंत्र
+मनुष्यों
+पत्रकार
+पेय
+विद्यमान
+मादा
+बोलने
+मना
+बेस
+सहयोगी
+हराया
+समीकरण
+लिखते
+फसल
+संहिता
+लें
+तिलक
+प्रोफेसर
+सीधा
+आकर्षक
+संज्ञा
+मोटे
+वार
+खगोलीय
+क्रमशः
+समर्थक
+स्नान
+नकारात्मक
+नक्षत्र
+पहुंचने
+चित्रकार
+दुर्लभ
+सिद्धान्त
+भाँति
+छाया
+पूंजी
+आलोचक
+अपनाया
+बेहद
+खड़ा
+सका
+उदय
+भूल
+यमुना
+क्रेडिट
+साउथ
+नैदानिक
+हिल
+में।
+फ
+नील
+प्रयोगशाला
+५२
+शासकों
+मा
+हिसाब
+इन्हीं
+रॉय
+गाय
+घायल
+ऋतु
+तार
+लम्बे
+३८
+संपन्न
+क्रिस
+कृत
+उतना
+नामकरण
+स्वाद
+मनोवैज्ञानिक
+भय
+नौसेना
+हावड़ा
+४८
+श्याम
+कार्यवाही
+हस्तक्षेप
+दंड
+दुबई
+किस्म
+अभियांत्रिकी
+फ़िल्मफ़ेयर
+मोहम्मद
+उर्जा
+पारित
+गोरखपुर
+अस्थायी
+स्तंभ
+मुसलमानों
+असामान्य
+कैथोलिक
+वर्गीकृत
+पाप
+मनीष
+श्रेणियों
+भरे
+४६
+पढ़ने
+बिल्कुल
+खुला
+उद्यम
+मूलतः
+जोड़ी
+युनाइटेड
+दरबार
+मद्रास
+निकालने
+विरासत
+संगम
+निहित
+गिर
+कथन
+दाब
+आवश्यकताओं
+कहानियों
+ऑक्सफोर्ड
+आफ
+उन्हीं
+आधा
+मर
+सोसाइटी
+ब्लॉग
+मल्ला
+कालाढूगी
+आकलन
+अत्यन्त
+पकड़
+चाहिये।
+भरी
+भाषण
+आधे
+रत्न
+टूर
+नाना
+संस्थानों
+कालेज
+शल्य
+।।
+नौकरी
+जुड़ने
+गा
+मास्टर
+किरदार
+कुशल
+पक्षियों
+अधिग्रहण
+मजबूर
+खड़ी
+बताते
+अनिल
+महाद्वीप
+हथियार
+कलकत्ता
+प्लास्टिक
+पायलट
+स्वस्थ
+जिनसे
+रचनाएँ
+शिवाजी
+परिक्रमा
+२००२
+भोपाल
+पटकथा
+खत्म
+ड्राइव
+रूपांतरण
+भक्त
+४२
+अन्यथा
+उच्चतम
+बढ़ता
+असर
+रेड
+घरों
+व्हाइट
+आना
+खाली
+जॉनी
+राहुल
+कमजोर
+ब्राज़ील
+श्रीमती
+चाय
+रखकर
+ॐ
+एपिसोड
+मुसलमान
+जाया
+एडवर्ड
+पारी
+बांध
+विस्फोट
+उर्फ
+गुरू
+डच
+प्रमाणित
+समग्र
+मतदान
+कण
+पाटी
+प्रोटोकॉल
+विकिपीडीया
+हिंसा
+आजादी
+तस्वीर
+४७
+चुनौती
+क्रांतिकारी
+शेर
+न्यूजीलैंड
+ऑक्सीजन
+बनते
+निगरानी
+व्यवस्थित
+सर्विस
+आखिरी
+चिन्ह
+समृद्ध
+प्रयासों
+रेस
+पाता
+खतरे
+उन्हे
+पटेल
+बादशाह
+गर्भ
+हमने
+चरम
+मुखर्जी
+चलकर
+पाउंड
+जातक
+टिप्पणीसूची
+न्यायाधीश
+५५
+अनुच्छेद
+शास्त्री
+हि
+५३
+पेशकश
+बिट
+गणेश
+जीवाणु
+संकलन
+पीड़ित
+ख़ास
+बेस्ट
+निकलने
+लोहे
+ऑव
+स्वर्ग
+सोसायटी
+बेल
+भट्ट
+बढ़ते
+दुर्घटना
+त्यौहार
+संगणक
+विनोद
+हालाँकि
+न्यूज़
+गहरी
+पब्लिक
+४३
+तीव्रता
+पेटेंट
+तिब्बत
+पीने
+इस्लामी
+भीड़
+बहादुर
+ड्रामा
+सुल्तान
+हटाए
+अन्तरविकि
+साक्षरता
+विक्टोरिया
+सिनसिनाटी
+मठ
+प्रतिदिन
+सम्बन्धी
+निबंध
+बनाती
+नव
+विषय।
+तेलुगु
+वीकीपीडीया
+ऊतक
+असली
+संसाधनों
+जानवर
+डाक
+बाग
+डर
+स्रोतों
+प्रतिबंध
+सोमेश्वर
+कब्जा
+रहित
+अवशेष
+वरिष्ठ
+बेल्जियम
+देशी
+जीतने
+रणनीति
+हें
+ताल
+द्रव्य
+खेला
+राजस्व
+रीति
+गयी।
+सजा
+उपयोगकर्ताओं
+बोस
+आलोक
+आत्म
+फ़्रांस
+किसान
+गणितीय
+ज्वालामुखी
+अंगों
+ों
+बनती
+४९
+कायम
+खिताब
+तुलसी
+लक्ष्मी
+समानता
+वयस्क
+शिष्य
+संतुलन
+अचानक
+नदियाँ
+नीतियों
+नागरिकों
+जाल
+नामित
+नेताओं
+पात्रों
+सिविल
+कप्तान
+दुश्मन
+चमक
+अर्जित
+मौखिक
+स्वभाव
+आनुवंशिक
+कितने
+भागीदारी
+चोरी
+रोशन
+आलोचकों
+बोल
+गहरे
+गेट
+स्तरीय
+बता
+बहस
+जावा
+खासकर
+पड़ने
+दौड़
+३७
+निर्माताओं
+विशेषताओं
+माई
+काट
+५६
+सृष्टि
+फाउंडेशन
+संप्रदाय
+उपर
+प्रखंड
+एटा
+प्रकरण
+अक्षय
+स्कॉटलैंड
+राजकुमार
+इंग्लिश
+आइपी
+ध्रुव
+मैक
+अनुमानित
+मधुमेह
+गौतम
+चरणों
+कहे
+ि
+महादेवी
+निम्नांकित
+कथित
+परिणामों
+लिखना
+गाड़ी
+कॉम
+लड़की
+उद्धृत
+ब्लॉक
+३९
+टेलीविज़न
+एकता
+खेलने
+कारों
+सांसद
+चौथे
+सहमति
+बचा
+गाइड
+भले
+हा
+कां
+रिसर्च
+ज़मीन
+आयुर्वेद
+बॉब
+मुद्दों
+सोडियम
+तरंग
+चालक
+बाघ
+साइंस
+ग्लोब
+सकल
+मिलान
+बताता
+जिलों
+जिम
+पत्रिकाओं
+लगाना
+वाशिंगटन
+बैंकिंग
+प्राणियों
+ै
+ईमेल
+३३
+निर्दिष्ट
+पोर्ट
+पुर्तगाली
+चीज़
+बाबू
+अखिल
+उदयपुर
+चोटी
+शक्तियों
+मापदंड
+ण
+घातक
+माध्यमिक
+मारा
+जरिए
+इकाइयों
+५४
+लेजर
+विधियों
+खण्ड
+देखना
+कान
+प्रस्तुति
+३४
+अक्षांश
+कइ
+मानकों
+गुफा
+रखती
+सुरक्षीत
+होम
+करियर
+कारकों
+पत्रकारिता
+पृष्ठ।
+प्रचलन
+अनुक्रम
+इगलास
+जूनियर
+विनिमय
+अनुवादक
+विद्यार्थी
+निर्यात
+शब्दार्थ
+केन्द्रित
+सम्पादन
+बोध
+ब्रह्मा
+फ़ोन
+चाल
+ध
+अंडे
+हनुमान
+ज़
+बास्केटबॉल
+समापन
+राग
+छोर
+साहिब
+शांत
+यॉर्क
+अद्भुत
+राष्ट्रों
+सदन
+प्रसंग
+मोशन
+तकनीकों
+परामर्श
+पैसे
+एवम
+पं
+पृथक
+सरदार
+माया
+मारने
+लेबल
+टु
+निचले
+अतिथि
+महादेव
+परियोजनाओं
+दर्शक
+विकिपीडियन
+जगदीश
+विकिपरियोजना
+मुख्यत
+सीमाओं
+मुकाबले
+प्रताप
+यौगिकों
+बजट
+५९
+अहमद
+चलाया
+अहमदाबाद
+अनुपम
+पूर्ति
+पिक्चर
+स्कूलों
+अंग्रेज
+स्वीकृति
+बसा
+धरोहर
+आंकड़े
+बैटरी
+फूलों
+बेटा
+गर्मियों
+प्रबन्धक
+जोड़े
+महाकाव्य
+जन्मे
+गानों
+वनों
+लेन
+बाह
+एकत्रित
+नेपाली
+अमीर
+नीदरलैंड
+कहानियाँ
+मेयर
+ऑपरेशन
+एक्शन
+श्रेणियाँ
+४१
+चुंबकीय
+मृत
+मुद्दे
+हित
+तोड़
+करे।
+बर्मा
+कहलगाँव
+कहाँ
+बैंकों
+मेले
+ग्रहों
+परे
+ब्रज
+ऑस्टिन
+सूचीबद्ध
+जरिये
+दूरभाष
+कितना
+प्रभावों
+वध
+वर्णमाला
+कितनी
+सचिव
+पवन
+मैक्स
+पिछला
+सौंदर्य
+लो
+खबर
+वाह्य
+प्रचालन
+री
+प्रभाकर
+पहल
+प्रभाग
+अनुसरण
+पहलू
+धूम्रपान
+रिकार्ड
+प्रशांत
+अक्षरों
+कथानक
+पारिवारिक
+लाहौर
+भाषाओँ
+यात्रियों
+घास
+जनपद
+विचारधारा
+बिलकुल
+सीता
+प्रतिष्ठा
+निशान
+टॉप
+अवैध
+दूरसंचार
+लौह
+अतीत
+छत
+इंक
+पूर्णिया
+कोर
+एलन
+उद्योगों
+निष्क्रिय
+क्यूबा
+वेग
+स्टील
+टाउन
+यूनान
+साफ़
+अलंकार
+विफल
+कुत्ते
+सम
+करना।
+मलेशिया
+तैयारी
+भव्य
+ार
+पुत्री
+इमामगंज
+वकील
+४४
+संकेतों
+मूल्यों
+बाई
+भ्रम
+पाल
+ब्याज
+गहन
+अंतराल
+चौथी
+प्रतिस्पर्धा
+निश्चय
+कारोबार
+बच
+कोटि
+साझा
+खुल
+लन्दन
+सार
+राज्यपाल
+पराजित
+स्नातकोत्तर
+रात्रि
+शानदार
+हॉलीवुड
+नाटकों
+पीला
+ब्राजील
+ऊंची
+पाये
+जोशीमठ
+सदस्यता
+पैरों
+हॉट
+आँख
+शिक्षक
+घिरा
+फ़ाइलों
+कथाओं
+बिगाड़
+रुपये
+तू
+संदेह
+लेखा
+क्रिसमस
+भूकंप
+बुरी
+हवेली
+बीकानेर
+जोधपुर
+कहलाते
+करनेवाले
+दशकों
+प्रदेशों
+कमरे
+वुल्फ़
+जितनी
+खतरनाक
+गुगल
+मामला
+रक्तचाप
+डा०
+रविवार
+लीये
+स्थापत्य
+वाहनों
+छूट
+हों।
+प्रो
+जातीय
+फंड
+चौक
+सिक्किम
+मिस्टर
+टूर्नामेंट
+रहमान
+जड़
+बनवाया
+इलाके
+गठबंधन
+किरण
+गोपाल
+कागज
+शुभ
+मिस
+एयरलाइंस
+लाखों
+तत्काल
+अवार्ड्स
+मौका
+गोल्ड
+व्यापारी
+हरी
+सलाहकार
+मनु
+फ़र्रूख़ाबाद
+अपवाद
+मूवी
+जोन्स
+फ्रॉम
+शिकारी
+ऑडियो
+महेश
+गौरव
+ऊँचा
+कब
+सतत
+पहाड़
+अनिरुद्ध
+अध्ययनों
+इंदिरा
+उपर्युक्त
+एकत्र
+महर्षि
+भर्ती
+सोचा
+गुरुआ
+शुरुआती
+अभियान्त्रिकी
+जनवादी
+पड़ी
+आंख
+फ़्राँस
+गोवा
+जैंती
+ट्रस्ट
+सर्जरी
+संयोग
+गिरफ्तार
+रामपुर
+समाजवादी
+सृजन
+बपतिस्मा
+कोष
+आराम
+मैचों
+बसे
+पैदल
+तलाश
+थियेटर
+शुष्क
+विश्वयुद्ध
+प्रतिद्वंदी
+परिवर्तनों
+एकदम
+भ्रूण
+मासिक
+द्वीपसमूह
+माला
+फैल
+नरेन्द्र
+स्टोन
+उठाया
+सारणी
+प्रारम्भिक
+बेतालघाट
+बीस
+त्रुटि
+संगठित
+क्लास
+एड
+आयरिश
+हू
+ललिता
+आग्रह
+संतान
+प्रबल
+नहर
+डॉन
+प्रवाहित
+स्पेनिश
+बनावट
+भाषाएं
+करा
+प्रोत्साहन
+भ्रष्टाचार
+उष्णकटिबंधीय
+गाना
+उपरांत
+पोलैंड
+बनायी
+आएगा।
+पादरी
+फैशन
+बजाए
+टूट
+सोनी
+गले
+मलेरिया
+बंगलौर
+पढ़ाई
+क्रिस्टल
+चौड़ाई
+जोकि
+व्यय
+मिला।
+विवेक
+अब्दुल
+परिवारों
+बाधा
+भूत
+रंगीन
+राजेश
+नींव
+हाइड्रोकार्बन
+पीले
+राकेश
+बुलाया
+इंस्पेक्टर
+परिचित
+वेतन
+इलेक्ट्रिक
+तरी
+खोला
+पदों
+मेन
+स्तरों
+रोजगार
+डोमेन
+मानता
+सेकंड
+६०
+ईसवी
+सिरे
+नाइट
+गभाना
+यथार्थ
+लि
+कीट
+भावनाओं
+नरेश
+करार
+जानता
+कार्यकाल
+सिडनी
+रमेश
+परिमाण
+भरत
+कार्ल
+खोल
+म्यूज़िक
+पठार
+शाखाओं
+गुप्ता
+कार्लो
+तिरवा
+वर्षीय
+चक्रवर्ती
+दिव्य
+चंद्र
+पावर
+विथ
+पूरक
+मुफ्त
+ग्रस्त
+रोज़
+समुदायों
+शैक्षणिक
+नीले
+भिन्नता
+फ़
+देन
+जाएँ
+अनेकों
+काउंसिल
+प्रतिद्वंद्वी
+माइक
+चालू
+सम्भव
+क्रियाओं
+शहीद
+विश्वविद्यालयों
+चौथा
+सदैव
+सुधीर
+नागपुर
+दु
+नवाब
+स्पर्श
+कोट
+दलों
+लगाए
+इतिहासकार
+ओवर
+फ़तेहाबाद
+ऑस्ट्रिया
+हार्ड
+मुकदमा
+स्टीव
+चीज
+पायी
+बादल
+आकाशगंगा
+आवरण
+भेजने
+सुनील
+कुश्ती
+ईसापूर्व
+२००
+मुनि
+स्
+बृहस्पति
+प्रयोगों
+बयान
+खाँ
+शब्दकोश
+स्वचालित
+सिम्बल
+पसंदीदा
+उत्तराधिकारी
+संसदीय
+गायन
+क्षमा
+आतंकवाद
+पत्रों
+हरिद्वार
+लगाकर
+अतएव
+गार्डन
+बैठे
+मदन
+चौहान
+चन्द्रमा
+उठाने
+जायें
+अर्ध
+तारीख
+डाउनलोड
+अनु
+ओलंपिक
+श्रंखला
+दिखाने
+अमिताभ
+मौर्य
+मुताबिक
+प्रपात
+फोटो
+लक्ष्मण
+मालूम
+देगा
+अपील
+लेंस
+स्पेस
+बिन्दु
+द्वीपों
+स्विट्ज़रलैंड
+अर्जेंटीना
+पूछा
+वोट
+अकाल
+शत्रु
+कबीर
+आचरण
+सफलतापूर्वक
+एक्सचेंज
+उत्तराखंड
+शिकायत
+शंकराचार्य
+धारावाहिक
+दृश्यों
+१९९०
+तूफान
+सड़कों
+अपेक्षित
+बाढ़
+प्रोजेक्ट
+पहुँचने
+हूं।
+ग्रांड
+उन्नति
+कच्चे
+स्वीकृत
+बहती
+व्यायाम
+प्रयोजन
+एरिक
+ऑटो
+इंटरसिटी
+सरलता
+उपनगरीय
+अनाज
+धातुओं
+संकल्प
+तेरे
+धूप
+वंशज
+परिपथ
+घोड़े
+मोक्ष
+तालाब
+असमर्थ
+श्रद्धा
+विनाश
+सापेक्ष
+अद्वितीय
+सराय
+सुरेश
+जनजाति
+ट्यूब
+रहकर
+कैम्ब्रिज
+श्वसन
+सुविधाएं
+सूत्रों
+बंध
+जंगलों
+नेत्र
+डीएनए
+बिलबोर्ड
+आदिवासी
+दिखने
+गाया
+आर्थर
+नैशनल
+सिक्के
+वायुयान
+समक्ष
+समतल
+पिछली
+छोड़े।
+विधा
+सीखने
+कालीन
+बौद्धिक
+विधेयक
+सक्सेना
+खा
+यूनियन
+परमात्मा
+संस्करणों
+योद्धा
+पैटर्न
+स्त्रियों
+कर्तव्य
+जातियाँ
+वंशावली
+कमाई
+पैसा
+वसंत
+कहलाती
+एंजिल्स
+अपोलो
+सिंहासन
+इनपुट
+बस्ती
+दीवारों
+प्राधिकरण
+संभवत
+भालू
+केबल
+पुष्प
+सिंचाई
+मानने
+कॉल
+क्रॉस
+अभिगम
+उपलब्धि
+राजनीतिज्ञ
+नोट्स
+बे
+मेजर
+ग्वालियर
+प्रजातियां
+लॉ
+प्रसन्न
+यूएस
+रहेगा
+बुरा
+रोल
+नली
+उक्त
+राजकीय
+हल्के
+हंगरी
+पैलेस
+बनकर
+फेर
+पुरे
+घड़ी
+कविताओं
+स्वरुप
+सेनानी
+अवयव
+अनुप्रयोगों
+कृतियों
+ध्रुवीय
+विल
+इंडोनेशिया
+बहुमत
+टिकट
+कठिनाई
+शासनकाल
+कार्यान्वयन
+दायित्व
+जर्सी
+वितरित
+मूर
+टर्मिनस
+सुन
+जाएगी
+फोर्ड
+दीपक
+चित्रकला
+गरीबी
+सेमी
+तात्पर्य
+संलग्न
+आश्चर्य
+मेहरा
+१९९८
+भंडार
+परिषद्
+लाइब्रेरी
+बंधन
+इण्डिया
+कोयला
+महमूद
+सुना
+नंदीग्राम
+संतोष
+यूके
+जागरण
+बदलकर
+नींद
+बचे
+किसानों
+खुशी
+स्पोर्ट्स
+बलों
+भंग
+कहानियां
+सफाई
+रहस्य
+कणों
+किशन
+वृत्त
+अरुण
+मानस
+प्रेमी
+हमलों
+जीते
+नमूने
+त्वरित
+नम्बर
+शरण
+आतंकवादी
+रंगमंच
+टुकड़े
+निकलता
+ठंडा
+खेत
+गेम्स
+राजेन्द्र
+तालिका
+तटीय
+दिनेश
+भंडारण
+निकला
+मध्यकालीन
+५००
+पान
+चक्कर
+ब्राउन
+वाणी
+असाधारण
+यकृत
+बोलते
+रोटी
+झूठ
+पौधा
+वेदों
+संक्रमित
+जितने
+खूब
+नाभिकीय
+ज्यामिति
+रेटिंग
+जिम्मेदारी
+प्रेमचंद
+एजेंट
+निरीक्षण
+लुईस
+नित्य
+मेमोरी
+उतनी
+उसपर
+पड़ोसी
+तुम्हें
+वचन
+लोकतंत्र
+पार्श्व
+संवेदनशील
+उत्पादित
+सीरीज
+कॉर्पोरेट
+सूचकांक
+चैनलों
+अनंत
+नीतिया
+रिकॉर्ड्स
+ज़रूरत
+भावी
+होल
+विवादास्पद
+पिनकोड
+सरकारों
+पहलुओं
+जादू
+तपस्या
+विहार
+मोटी
+रुपए
+अपितु
+व्यंग्य
+सीधी
+सिर्फ़
+गुवाहाटी
+बेच
+नाटकीय
+शोर
+पुराणों
+मरीज
+वाजपेयी
+तिवारी
+रही।
+ब्रेक
+फैले
+विन्यास
+भाप
+थोड़े
+सर्वोत्तम
+शशि
+पार्वती
+रचनाकाल
+अदा
+गयीं
+पुर्णिया
+बॉन्ड
+बिन
+मोंटे
+नाक
+दीक्षित
+जिनमे
+अवलोकन
+नस्ल
+डेनमार्क
+वरुण
+विभक्त
+सैकड़ों
+अनुभूति
+पंजीकृत
+मतभेद
+कॉमेडी
+कलात्मक
+निकाय
+तरफ़
+आणि
+साथियों
+गुलाब
+झिल्ली
+सोना
+संश्लेषण
+इलाकों
+पण्डित
+आया।
+रेसिंग
+खपत
+टेलीफोन
+पड़ते
+दिलीप
+ई०
+एकादशी
+प्रतिबंधित
+फलों
+साइड
+उपासना
+खोटे
+प्रिक्स
+एचआईवी
+आमंत्रित
+फार्म
+इसपर
+रेंज
+१९९९
+प्रयाग
+मंगोल
+शासित
+रद्द
+अजय
+भाजपा
+आईएसबीएन
+सुमित
+एवम्
+रजिस्टर
+विकीस्रोत
+इंदौर
+बोइंग
+अमृतसर
+मकान
+पारिस्थितिकी
+मैड्रिड
+समन्वय
+अन्ना
+लोहा
+कम्युनिस्ट
+गण
+अवसरों
+ब्यूरो
+चूँकि
+खुली
+तन्त्र
+राजपूत
+समझते
+बिहारी
+वैष्णव
+चैंपियनशिप
+प्रतिकूल
+सिंड्रोम
+बंबई
+अमृतपुर
+ख्याति
+पुर्तगाल
+क्यूँ
+घ
+नारी
+अनुभाग
+मैरी
+गर्भाशय
+सर्व
+पूर्ववर्ती
+चतुर्थ
+इमारतों
+रेजिस्ट्रेशन
+प्रभु
+अस्वीकार
+साक्ष्य
+वॉ
+बढ़कर
+इनकार
+सांस
+प्रतिवर्ष
+भाषी
+बढा
+मूत्र
+अरारिया
+निकलती
+क्रिटिक्स
+धारक
+उपयोगिता
+त्योहार
+समेत
+प्रतिरक्षा
+बटन
+समर्थ
+दा
+नगरी
+तेज़
+भूतपूर्व
+देखता
+दमन
+अनुचित
+श्रीवास्तव
+हट
+प्रशंसकों
+भंडा
+तथ्यों
+दस्तावेज
+ऑपरेटिंग
+कोशिकाएं
+वाणिज्य
+पोषक
+धीमी
+वियतनाम
+स्कॉट
+रहीं
+घाव
+प्रावधान
+१९९२
+बैक
+श्रीराम
+मुकाबला
+स्टेट्स
+पादप
+गणतंत्र
+योजनाओं
+रोजर
+हार्मोन
+उत्पादक
+टेक्सास
+बेहतरीन
+फ़्रांसिसी
+राजस्थानी
+लगाते
+बीटा
+मान्य
+उद्धरण
+एज
+उद्घाटन
+पूर्वोत्तर
+हार्डी
+यहा
+शैलियों
+ऋग्वेद
+तमाम
+बेन
+सुभाष
+प्रशिक्षित
+दुबारा
+भीतरी
+प्रिंस
+हड्डी
+मल्ली
+बेचने
+महत्त्व
+आक्रामक
+कार्यकर्ता
+कटौती
+सोमवार
+गिर्द
+शुरूआती
+तिहाई
+खरीदने
+इट
+बिजनेस
+असंभव
+डिज़्नी
+जानकी
+ली।
+तें
+बने।
+खेले
+दादा
+पृथ्वीराज
+सांख्यिकी
+हुईं
+केविन
+बनारस
+रोशनी
+आरती
+पीछा
+स्थानांतरण
+रिश्ते
+बर्तन
+परिस्थिति
+बोले
+राष्ट्रीयता
+बलि
+इंजीनियर
+प्रमेय
+बुक्स
+उनपर
+छंद
+गुंजन
+टॉवर
+शाब्दिक
+स्वप्न
+सुधारने
+यूरो
+अवध
+तत्त्व
+निधि
+ललित
+भांति
+विमानों
+जलप्रपात
+चाहती
+आंकड़ों
+तेज़ी
+मैनेजमेंट
+मैट्रिक्स
+राजभाषा
+आयाम
+गुड
+पाली
+सनहौला
+पारस्परिक
+जंग
+पिक्चर्स
+इनको
+आस्था
+गुलाबी
+आजाद
+टेक
+ऊंचा
+एतमादपुर
+ब्लोक
+प्रतिनिधियों
+स्टेशनों
+हालत
+१९९१
+अटलांटिक
+ऊँचे
+वेबसाईट
+पत्ते
+आलू
+इन्द्र
+परिकल्पना
+सुनने
+गुलशन
+हज़ार
+कम्प्यूटिंग
+नियुक्ति
+पहुँचा
+विशेषताएं
+आयात
+खुदरा
+लैंड
+मग
+महा
+फ़िर
+अनुयायी
+काफलीगैर
+डाउन
+ओबामा
+कैद
+सूजन
+उपदेश
+विवेचन
+मोटा
+नारंगी
+धर्मों
+कुमारी
+बंदी
+ख़त्म
+अल्प
+कोटा
+चीजों
+पहाड़ियों
+८०
+सर्किट
+स्रोतहीन
+दुकान
+हंस
+सैद्धांतिक
+किरन
+देखें।
+तलवार
+सबके
+ब्रदर्स
+दोषी
+टेलर
+बॉल
+कटाई
+वाद
+पक्षों
+फ्रैंक
+नगरों
+वाहक
+विश्वसनीय
+समस्याएं
+पत्थरों
+कार्टून
+जि
+बीसवीं
+तिब्बती
+गो
+भेंट
+जगहों
+निष्पादन
+विक्रेता
+खगोल
+रोज
+कसम
+स्मरण
+क्रोध
+कॉमिक्स
+सूर्यवंशी
+पोप
+भेजे
+्य
+किरौली
+सख्त
+ग्रीष्मकालीन
+विल्सन
+सुदूर
+ढांचे
+जगन्नाथ
+ड्राइवर
+गांवों
+कश्मीरी
+स्वीडिश
+वशिष्ठ
+पीड़ा
+कहकर
+नैतिकता
+वस्तुत
+औषधीय
+मैट
+ज्योति
+नगला
+महापौर
+गठित
+प्रदाता
+श्
+आर्ट्स
+हटाना
+ऊष्मा
+सकने
+मरने
+ग्रीस
+मिश्रा
+हमसे
+आपसे
+क्वीन
+गिनती
+शिल्प
+मनोनीत
+एकड़
+रोकथाम
+हितों
+आशू
+अधिकृत
+इर्द
+सांता
+खुदाई
+स्टीफन
+विश्वकोश
+लायक
+विश्वनाथ
+गीतकार
+मुमताज़
+रूचि
+इराक
+लम्बा
+ग़ैर
+वॉशिंगटन
+आपसी
+भूमिगत
+भरपूर
+रावण
+वन्य
+सौरभ
+जुड़
+विद्युत्
+अद्यतन
+जीएसएम
+मैकमोहन
+सेतु
+दूरदर्शन
+संवैधानिक
+जीवाश्म
+डबल
+हानिकारक
+दर्पण
+पूजन
+विलयन
+िया
+लता
+उपहार
+क़ानून
+थिएटर
+परिचालन
+एकीकरण
+प्लेट
+हार्डवेयर
+समावेश
+संचिका
+अपशिष्ट
+मनमोहन
+फाइबर
+भारतीयों
+दुसरे
+आंखों
+संस्कृतियों
+यंग
+सदियों
+मत्स्य
+युक्ति
+फ्रांसिस्को
+बर्लिन
+लौटने
+मेहता
+क्षण
+पाश्चात्य
+गामा
+कैमरा
+ताजमहल
+सर्च
+बना।
+तल्ली
+साधनों
+पहचाना
+राजा।
+मेरठ
+जिसको
+मधु
+रिश्ता
+धूल
+गायब
+मोर
+सीरीज़
+इति
+सें
+सामुदायिक
+अनुदान
+ड्रम
+बडा
+कालिदास
+ब्रूस
+क्षय
+मातृवंश
+ट्रिपल
+प्रगतिशील
+गोस्वामी
+शनिवार
+हल्का
+हिन्दुओं
+फैली
+विष
+गर्भावस्था
+विस्तारित
+मिमी
+बा
+डेल्टा
+आँखों
+दीर्घ
+गंतव्य
+गणितज्ञ
+बिली
+बल्लेबाज
+क्लोराइड
+बालों
+मैनचेस्टर
+यु
+निर्णायक
+इंगित
+मयुर
+साप्ताहिक
+वैशाली
+पूर्णतया
+बच्चा
+अक्ष
+भविष्यवाणी
+भ्रमण
+हांगकांग
+ब्लेक
+रेस्तरां
+कृपा
+परेशान
+विकासशील
+मांसपेशियों
+गोविन्द
+प्राकृत
+कथाएँ
+गुलाम
+व्यस्त
+मार्गदर्शन
+कोंच
+कट
+प्रतिस्थापित
+वैभव
+पहने
+पाठकों
+बातकरें
+डॉग
+विकिमीडिया
+बेदी
+पोशाक
+चंद्रमा
+छिद्र
+इमारतें
+माउंट
+सिफारिश
+होगन
+उज्जैन
+समर्थित
+ब्रह्माण्ड
+रसूल
+श्लोक
+राहत
+आखिर
+एम्
+दाल
+पकड़ने
+मुँह
+उत्साह
+गर्दन
+तुलनात्मक
+काटने
+पाक
+महारानी
+ग्रंथि
+जरुर
+यूरोपियन
+आत्महत्या
+शर्त
+चुम्बकीय
+सम्प्रदाय
+नवीनतम
+हीरो
+मशीनों
+जयंती
+मिथुन
+उद्देश्यों
+सामयिक
+अकेला
+परिवेश
+मोड
+लवण
+चिली
+रखरखाव
+बोलचाल
+अभिलेख
+चाँद
+लें।
+सेनाओं
+अखबार
+दिखा
+रूपरेखा
+भास्कर
+समाधि
+विंडोज
+बनाया।
+भयंकर
+अमृत
+अरुणा
+ऊंचे
+खेर
+दोबारा
+बाध्य
+लगी।
+नागर
+उपन्यासों
+हीन्दी
+नाट्य
+जनक
+नमूना
+टीमों
+आउटपुट
+जोस
+कोरियाई
+मरम्मत
+डाक्टर
+सूरा
+कष्ट
+परीक्षणों
+बाएं
+भरने
+वेन
+केस
+महिलाएं
+लुप्त
+फ्रेम
+द्विवेदी
+असरानी
+शोषण
+नियमितता
+इंसान
+पद्य
+वायुमंडल
+पोल
+विलुप्त
+अपूर्ण
+बेचा
+लिनक्स
+कडी
+सतीश
+बहरहाल
+आयी
+हिन्दु
+मल
+बताने
+श्रीनगर
+लड़ने
+टोक्यो
+ऊँची
+पर्ल
+पितृवंश
+नी
+दीर्घा
+धार
+मंदी
+फ्री
+घंटा
+दोपहर
+इंस्टिट्यूट
+गुर्दे
+एचटीएमएल
+रजत
+अवकाश
+सीबीएस
+पाना
+होती।
+फेसबुक
+भगवानपुर
+पतली
+सीट
+मोड़
+मक्का
+स्पेक्ट्रम
+संरचनाओं
+इसमे
+बुध
+ब्लूज़
+अवसाद
+अफगानिस्तान
+पंजीकरण
+जरुरत
+अवरोध
+ब्राउज़र
+टाइगर
+विनिर्माण
+जालघर
+विज्ञापनों
+बॉट
+ग्यारह
+मुजफ्फरपुर
+गिनी
+परी
+मिलेगा
+कस्बे
+भाषाई
+बारी
+माँग
+गैलरी
+मिलन
+शुक्र
+आर्मेनिया
+इंस्टीट्यूट
+आत्मकथा
+सदस्योंको
+प्रतिपादन
+टर्मिनल
+रहेगा।
+पेड़ों
+मिली।
+कमीशन
+योनि
+फसलों
+गतिशील
+भी।
+संचरण
+प्रभुत्व
+उपक्रम
+समुचित
+दक्षता
+द्रविड़
+बन्द
+दिखता
+मध्यप्रदेश
+सारांश
+भीम
+अस्तित्वहीन
+हथियारों
+खुराक
+प्रकारों
+तेरा
+ताकत
+भगवान्
+लेक
+समकक्ष
+देशांतर
+ै।
+जोसेफ
+आज़ाद
+सामान्यत
+उपभोग
+भीष्म
+ऊतकों
+खिलाफ़
+लोकमान्य
+अन
+राजू
+अस्थि
+दरवाजे
+राजनेता
+आघात
+उपमहाद्वीप
+प्रख्यात
+टोनी
+टुल्सका
+विफलता
+स्टोरी
+बैठ
+बनना
+स्वतः
+भाषाविज्ञान
+दृढ़
+अर्थात्‌
+शी
+पचास
+प्रसिद्धि
+अपराधी
+डाली
+हरि
+डकोटा
+कोहली
+प्लेयर
+आश्रय
+नाग
+बिस्मिल
+छात्रवृति
+मिनेसोटा
+लाए
+सकें।
+चुनावों
+ब्रिज
+चिंतन
+बिगाड
+विमर्श
+पहुंचे
+होंगे।
+वैसा
+भूख
+दिखें
+नॉर्थ
+अवस्थित
+घेरे
+स्ट्रोक
+सर्बिया
+असल
+हिन्दुस्तानी
+घन
+वीज़ा
+महोत्सव
+घटकों
+बढ़ी
+करवा
+सुनकर
+रावल
+घट
+प्रायद्वीप
+स्वाधीनता
+विशेषज्ञों
+प्रबंधकोने
+कैलिन्डर
+धनरूआ
+डेली
+किलो
+जाट
+अधिकारिक
+माहौल
+सीटें
+पुरातत्व
+पीपल
+लीटर
+अनुकूलन
+गेंदबाज़ी
+शीह
+वायुसेना
+सूर्यगढा
+उन्होनें
+सिंध
+इधर
+टैंक
+पंच
+भूमध्य
+अफ़्रीकी
+डांस
+बलिया
+एड्स
+जनन
+जंतु
+समझना
+ग्रन्थों
+सैम
+गुरुत्वाकर्षण
+कोमल
+जायेंगे
+थाईलैंड
+टेलिविज़न
+दायर
+ज़िले
+त्रिपाठी
+प्राचीनतम
+विदेशों
+करी
+पढ़ा
+पर्वतीय
+नाइट्रोजन
+परशुराम
+स्वतन्त्रता
+चार्ज
+मेहनत
+फिलिप
+पेट्रोलियम
+नदियां
+पिंड
+उत्तरार्ध
+लेनदेन
+दीर्घकालिक
+आयतन
+मूलभूत
+टनकपुर
+डाटाबेस
+औरत
+नकल
+डि
+चैंपियन
+मोती
+होनेवाले
+दिमाग
+टेक्स्ट
+जीवनचरित
+मणिपुर
+फील्ड
+प्रक्षेपण
+निकले
+खड़गपुर
+करन
+९१
+प्रदर्शनी
+अनुष्ठान
+वक्र
+संबोधित
+शिविर
+वास्तविकता
+गोआ
+मेटल
+भगत
+सवार
+मजदूर
+शतक
+मानवता
+वॉन
+बढ़ाया
+दानव
+सदृश
+१९८९
+विभागों
+कमाल
+बचत
+मिर्च
+कॉफी
+बडे
+कीं
+फर्स्ट
+स्तन
+कोने
+संसारके
+१९७२
+डुमरिया
+क्
+आवागमन
+१९८०
+होम्स
+संकलित
+पत्तियों
+सूखे
+मुलाकात
+लास
+सनातन
+सामग्रियों
+कुत्तों
+रोबोट
+खैरागढ़
+कर्नल
+राखी
+आधारभूत
+पालीगंज
+स्पेशल
+संजीव
+अग्रवाल
+आस्ट्रेलिया
+आधी
+सूरत
+संक्रामक
+मुझसे
+मुग़ल
+वोल्टेज
+अणुओं
+ज़रा
+सील
+खनन
+समानांतर
+बोला
+ग्रे
+ष
+भागवत
+रंजीत
+मीनार
+पूर्णागिरी
+बीरबल
+गायत्री
+जबलपुर
+उजागर
+सशस्त्र
+कोच
+प्रश्नों
+बुंदेलखंड
+बडी
+बदलते
+पुर
+जीवविज्ञान
+राह
+प्रशंसक
+पर्यावरणीय
+लड़कियों
+स्टोर
+संगत
+प्रोफ़ेसर
+एलिस
+हिंद
+पूल
+भि
+९०
+भावनात्मक
+प्राथमिकता
+वाष्प
+ओल्ड
+आज्ञा
+औजार
+गैसों
+व्हिस्की
+रोका
+कहती
+जहाजों
+सशक्त
+दिवसीय
+उतार
+शान्ति
+वृक्षों
+प्रचुर
+प्रसव
+७०
+संरचनात्मक
+फीचर
+फॉक्स
+देरी
+पुरूष
+कीबोर्ड
+लाइट
+शिलालेख
+सपना
+व्युत्पत्ति
+कद
+सजीव
+लोकतांत्रिक
+स्राव
+विन्डोज़
+शॉट
+चिह्नित
+उधार
+जेट
+चे
+युधिष्ठिर
+माधव
+आसन
+संख्याओं
+शेख
+घूमने
+आक्सीजन
+राइट
+नियत
+इतिहासकारों
+एनरॉन
+रु
+पारम्परिक
+व्
+सर्वथा
+वाद्य
+आपदा
+दरभंगा
+जात
+१९७१
+लाभदायक
+म्यूजिक
+दावे
+वोल्डेमॉर्ट
+भारतवर्ष
+जोकर
+राणा
+कादर
+गढ़
+कनालीछीना
+मुकेश
+जाएं
+क्लार्क
+बॉबी
+सम्पन्न
+भूरे
+शोधकर्ताओं
+पूर्ववत
+अहिंसा
+बीमार
+जूते
+फाइल
+नारियल
+अमरीश
+अवतरण
+छेद
+शर्करा
+सेनापति
+एक्सेस
+वस्तुएं
+वादक
+दांत
+योगी
+चोल
+परिष्कृत
+श्रमिक
+नामांकरण
+सबको
+जिसपर
+इलेक्ट्रॉन
+महिमा
+क्षैतिज
+उत्तरदायी
+शूटिंग
+कारखाने
+आरक्षण
+आरेख
+किए।
+रो
+यों
+घटनाएं
+बाइबिल
+दम
+वार्ड
+ज़रूरी
+औचित्य
+एव
+१९७०
+तीस
+यूनिट
+खेलते
+डेटाबेस
+मामूली
+सफर
+अध्यक्षता
+आदर
+कॉर्पोरेशन
+चैतन्य
+िक
+निरपेक्ष
+निकोलस
+आसमान
+विश्राम
+वर्जीनिया
+अभिनीत
+आन
+संरक्षक
+दाता
+तेरी
+जॉनसन
+अल्कोहल
+दिस
+दर्शाते
+अन्वेषण
+लगाई
+जीने
+टीबी
+३००
+उदाहरणार्थ
+करण
+चंडीगढ़
+शरद
+कास्त्रो
+सहकारी
+छुट्टी
+स्थिरता
+जोड़ता
+कैल्शियम
+वुड्स
+ित
+सपने
+इत्यादि।
+प्रजा
+सेक्स
+शुक्रवार
+सर्दियों
+चीजें
+नाव
+फर्म
+हॉकी
+कहां
+विमानक्षेत्रों
+१९४७
+चढ़ाई
+परवर्ती
+क्षत्रिय
+ब्राह्मणों
+कराता
+नौबतपुर
+आयन
+आइ
+प्रवर्तन
+लिटिल
+स्वत
+नासा
+तंग
+रक्षक
+ग्रोवर
+शिवपुरी
+सीडी
+गौर
+बतौर
+कल्प
+साधु
+इकाइयाँ
+पढ़
+दीक्षा
+घंटों
+करेगी
+उदहारण
+लीवर
+सती
+बियर
+हार्वर्ड
+सहारे
+दक्ष
+१९९६
+अभिषेक
+तुम्हारी
+रेगिस्तान
+अभयारण्य
+चाचा
+प्रशासकीय
+टावर
+अनुकरण
+जें
+ऊन
+फायर
+जैसलमेर
+कविताएँ
+विक्रमादित्य
+लड़के
+न्यायिक
+आपराधिक
+निंदा
+सेठ
+गत
+दुर्योधन
+गगनचुम्बी
+हीरा
+१९९५
+वैन
+मिशेल
+मालुम
+जिमी
+रिपब्लिकन
+चटर्जी
+पेपर
+बोस्टन
+व्यापारियों
+शान
+सुप्रसिद्ध
+सचिन
+हु
+राजकुमारी
+निवारण
+विकृत
+त्रिपुरा
+लेबनान
+परेशानी
+१९९७
+देवलथल
+प्रत्यय
+मरीजों
+स्‍थान
+फतेहपुर
+ह्रदय
+अध्यापन
+लीड्स
+औरंगजेब
+वस्तुएँ
+निवेशकों
+सरोवर
+एंडी
+दिनांक
+कंट्री
+लीप
+गंध
+श्रेणियां
+आरक्षित
+मारुति
+प्रशासक
+ज़िन्दगी
+जन्मस्थान
+वॉल
+भाइयों
+सहकुंड
+शेयरों
+कवरेज
+धाम
+कर्ता
+वाल्मीकि
+संग
+सेल्सियस
+सलीम
+सूक्ष्मदर्शी
+यांत्रिकी
+इलाका
+रियल
+पंकज
+विशेषताएँ
+मकबरा
+प्रहार
+अजमेर
+अभिगमन
+केशव
+मयूर
+धनी
+ऑक्साइड
+अरुणाचल
+उपलब्धता
+नजदीकी
+इंजीनियरी
+डीन
+उपनिषद्
+जरूर
+प्रखण्ड।
+ब्रह्मांड
+शीत
+पहाड़ों
+एक्ट
+विण्डोज़
+छठी
+कश्यप
+वार्नर
+उ०व०
+बुश
+१९६०
+सन्त
+पारसी
+खोजने
+कुंजी
+रोमानिया
+इकट्ठा
+लय
+शस्त्र
+फलन
+तुलसीदास
+आदित्य
+जगदीशपुर
+नीम
+इयर
+सामान्यतया
+चार्ली
+जानेवाले
+एजेंसियों
+पाटिल
+सिगरेट
+बरकरार
+पाठ्य
+साहनी
+जोड़कर
+शैल
+पाचन
+लेट
+से।
+अनावश्यक
+गतिविधियाँ
+विषयक
+शर्तों
+असंख्य
+याहू
+विक्रय
+राष्ट्रमंडल
+ऑस्ट्रेलियन
+बलिदान
+उपेक्षा
+पाती
+गौरी
+संचित
+मार्केट
+सिकंदर
+सीरिया
+अभिक्रिया
+टक्कर
+दहन
+हैमिल्टन
+घोष
+समाजशास्त्र
+भाग्य
+चट्टानों
+साझेदारी
+पठन
+उत्तेजित
+अवशोषण
+चिकित्सकीय
+अपमान
+ओजोन
+स्तूप
+वयस्कों
+ट्यूमर
+रॉ
+इंटरफेस
+टेबल
+संज्ञानात्मक
+सच्चे
+कपड़ा
+वक़्त
+ऐल्बम
+मित्रों
+बीहता
+उदाहरणों
+ऑस्कर
+पृथक्
+घी
+अं
+सुई
+झलक
+विराम
+फोर्ट
+पुरस्कारों
+इज़
+एनबीसी
+रखा।
+सत्येन्द्र
+वर्णक्रम
+चांदी
+वेगास
+नें
+वषीश्ठ
+श्र
+बगैर
+पुनर्निर्माण
+आदान
+हिटलर
+क्षतिग्रस्त
+ज्यों
+प्रसंस्करण
+सुरंग
+शाकाहारी
+धनुष
+वैचारिक
+मधुर
+गायिका
+प्रोफाइल
+प्रतिरोधी
+उपज
+संवर्धन
+चेहरा
+बाँध
+कोर्स
+स्पेनी
+परिप्रेक्ष्य
+प्रतापगढ़
+महानगर
+सुनाई
+गद्दी
+वास्तु
+निर्देशांक
+आँखें
+व्यतीत
+उन्नीसवीं
+गिरने
+भावों
+सांख्यिकीय
+आशय
+भगवती
+साधारणतया
+भोज
+मुराद
+रवी
+प्लेस
+परंपराओं
+हिप
+डार्क
+चुन
+साजन
+परिदृश्य
+रज़ा
+ताइवान
+सवारी
+देखिये
+त्रिकोण
+कपड़ों
+पद्धतियों
+अपनाने
+स्त्रोत
+खिज़िरसराय
+समर
+जड़ी
+वेदव्यास
+१९६५
+चलन
+जिव्
+सौंप
+औपनिवेशिक
+चिकित्सीय
+ट्रेड
+स्वच्छ
+बुरे
+डैनियल
+मंगलवार
+पूर्वज
+उष्मा
+चिकित्सकों
+रूपांतरित
+जंतुओं
+नारद
+पैकेज
+नागरी
+पल
+बहुविकल्पी
+तथाकथित
+कार्यक्षेत्र
+पंख
+अवॉर्ड
+मसौढी
+तम्बाकू
+लहर
+बीमारियों
+निरूपण
+साइकिल
+थीम
+क्रान्तिकारी
+इंग्लैण्ड
+सर्वत्र
+जॉर्जिया
+शेट्टी
+छाप
+मलिक
+हैमबर्ग
+स्वदेशी
+सूचक
+१९६२
+धारचुला
+चर्चिल
+रिलायंस
+ईस
+ती
+संकर
+विजुअल
+उदार
+उद्गम
+पंचमी
+मंजूरी
+अनन्त
+प्रायोजित
+नेट
+मालवा
+लाई
+बगल
+धर्मेन्द्र
+नाश
+फीफा
+नगरपालिका
+टेप
+खुर्द
+मार्गों
+धमकी
+शिवलिंग
+प्रासंगिक
+धरहरा
+मारिया
+विवादित
+मेक्सिकन
+१९८६
+उपायों
+दरअसल
+सम्पादक
+वृत्तचित्र
+सिंगल
+लुई
+विद्यार्थियों
+मुद्दा
+फैसले
+आए।
+अलगाव
+मिशिगन
+धान
+भयानक
+पिट
+दिखाए
+ान
+चाप
+पहनने
+विशेषज्ञता
+पैट्रिक
+इनमे
+चर
+कुत्ता
+निर्वाण
+दण्ड
+नागरिकता
+दुकानों
+वर्चुअल
+लंका
+शॉन
+ब्लड
+जैक्सन
+जलीय
+अमास
+कड़ियों
+अनुसूचित
+रेत
+गारंटी
+दिशाओं
+स्टैनफोर्ड
+मूलत
+डेनियल
+परि
+सेवक
+अमृता
+शताब्दियों
+जायेगी
+दिलचस्पी
+नाईट
+मॉडलों
+हान
+स्वायत्त
+ज्वर
+जवाहरलाल
+आगामी
+कूद
+बुधवार
+राक्षस
+आयेगा।
+इंटर
+वांछित
+धमनी
+सुलभ
+बाण
+वाई
+पुरातात्विक
+गौड़
+सामवेद
+नाभिक
+अध्यापक
+समाजवाद
+उद्भव
+डैनी
+चक्रवात
+फैलाव
+एंटीबायोटिक
+चर्चित
+जितेन्द्र
+उपनिवेश
+लास्ट
+१९७५
+डाई
+गुणा
+सूट
+इलेक्ट्रॉनिक्स
+स्क्वायर
+डाले
+दुःख
+कुंड
+सांचे
+चंपारण
+प्रवास
+दुख
+अधिवेशन
+भरोसा
+तप
+महामारी
+सेब
+जेरी
+हसन
+ऑर्डर
+घोड़ा
+पासवर्ड
+खारिज
+ख़ुद
+इन्होने
+डेविस
+सरन
+प्लाज्मा
+खुलासा
+स्कॉटिश
+टोरंटो
+बेकर
+प्रतीक्षा
+कराते
+क्षमताओं
+पांडे
+हॉप
+कांच
+मणि
+ऐतरेय
+णी
+न्यूज
+संतुलित
+सीला
+विरूद्ध
+द्वितीयक
+ट्रक
+भेदभाव
+निराला
+नजदीक
+भाष्य
+आयेगा
+सहन
+उस्ताद
+नॉर्वे
+बैठा
+संस्कारों
+घने
+गोपनीयता
+स्तम्भ
+वैमानिक
+पंत
+भक्तों
+सम्भावना
+श्वास
+ओवेन
+जगत्
+फायदा
+तस्वीरें
+रुक
+निषेध
+नेटवर्किंग
+आयरन
+मॉडलिंग
+१९८४
+चंद
+शिमला
+कोल
+मनोज
+बैल
+झा
+केन्द्रों
+केप
+एकाधिक
+कुरुक्षेत्र
+डिएगो
+कराना
+फिल्मी
+ठहराया
+जिल्ला
+अमीरात
+ज़िला
+प्रतिस्थापन
+मूर्तियों
+कूट
+साहस
+बेबी
+हाइब्रिड
+पेशी
+तिरुपति
+सोलह
+इयान
+डिक्शनरी
+ताज
+बहुमूल्य
+सुगंधित
+पैनल
+वाटर
+नकली
+टैक्सी
+अस्त्र
+बुखार
+जानना
+उत्परिवर्तन
+निमित्त
+द्वारका
+फिलिप्स
+कांगो
+आइलैंड
+दाढ़ीकेश
+आक्साइड
+मिल्वौकी
+पर्वतों
+१९८५
+ढाल
+ईस्टर
+वर्षो
+उधर
+बिल्डिंग
+ज़ोर
+निर्भरता
+सिन्धु
+अनौपचारिक
+यम
+योर
+नवजात
+नियंत्रक
+अनुभवों
+विज्ञानी
+लगाये
+वर्णों
+स्वतन्त्र
+अलौकिक
+हीं
+बदलता
+डालते
+चौड़ी
+आशीर्वाद
+गोद
+उपाध्याय
+जिनको
+स्टर्लिंग
+क्यू
+सिपाही
+मासने
+अनुभवी
+अपभ्रंश
+सलमान
+दर्जे
+आईसीसी
+मेँ
+किलोग्राम
+इंजनों
+खुश
+किंग्स
+व्यर्थ
+प्राप्तकर्ता
+सल्तनत
+उत
+सीख
+१०००
+अवयवों
+जिक्र
+दीप
+ज्ञानपीठ
+कोयले
+्र
+संदिग्ध
+नम
+परमाणुओं
+मछलियों
+मार्टिना
+स्कैन
+मादक
+अधिवर्ष
+महान्
+लेखांकन
+आजीवन
+बेला
+बाली
+दाहिने
+उठ
+भूरा
+कोस्ट
+यंत्रों
+दलित
+पर्याय
+प्रस्थान
+रेखाओं
+ईस्वी
+पालतू
+गिरा
+बरौनी
+१९९४
+प्लग
+दोहरी
+एडम्स
+अजीत
+सावधानी
+थ्री
+आशंका
+सिल्वर
+न्यूयार्क
+रोमांस
+डॉट
+कॉपी
+बाप
+ईंट
+गर्भवती
+लाला
+घूर्णन
+जया
+यशवंतपुर
+पागल
+जागरूकता
+कंठ
+आईटी
+पत्तों
+समर्थकों
+टूल
+राउंड
+अन्‍य
+ग्रिड
+दंत
+हिंसक
+तार्किक
+विशुद्ध
+बैठने
+मुद्रण
+सकती।
+पहुंचाने
+कंधे
+परिश्रम
+खोलने
+वृत्तांत
+सिस्टम्स
+धरातल
+सांचा
+संवेदनशीलता
+जिंदगी
+पूर्णतः
+पुरस्कृत
+सराहना
+अन्न
+मीठा
+संतों
+डीसी
+एंड्रयू
+़
+बृहदारण्यक
+टुकड़ों
+रिजर्व
+खंडन
+उपभोक्ताओं
+टिम
+नागार्जुन
+श्रवण
+प्रविष्टियों
+कीटों
+रेसलिंग
+मैदानों
+अभिनव
+एनिमेटेड
+दीन
+बारिश
+मॉल
+डेथ
+क्रान्ति
+छोड़ा
+पुण्य
+प्रतियोगिताओं
+देह
+माइक्रोफोन
+मनाने
+किम
+हेल्थ
+अभिव्यक्त
+दस्तावेजों
+बेरी
+अपहरण
+टोपी
+बाजारों
+संग्रहित
+देखो
+बहने
+भली
+चतुर्वेदी
+विघटन
+रियासत
+भवनों
+जायेगा।
+छठे
+अपर्याप्त
+वस्तुतः
+कार्बोहाइड्रेट
+इंजेक्शन
+नायर
+विद्रोही
+बैटमैन
+गोल्फ
+प्रतिज्ञा
+जरा
+पीस
+बदलती
+खरीदा
+इंटरनैशनल
+झुकाव
+लाना
+उत्थान
+सुसज्जित
+अर्चना
+ओं
+लोड
+कमांडर
+१९८२
+विद्यालयों
+व्याप्त
+आतंक
+अनियमित
+विंग
+चंद्रशेखर
+जाहिर
+त्र
+काटकर
+गिल
+इवान
+एंटी
+जाता।
+प्रदीप
+वकालत
+परजीवी
+प्रणालियां
+अहम
+केले
+चन्द्रगुप्त
+इक्विटी
+दोस्तों
+विद्यापीठ
+समर्पण
+जिल
+तोड़ने
+फिलाडेल्फिया
+पंचायत
+चिड़ियाघर
+नर्मदा
+विनियमन
+परम्परागत
+लॉजिक
+बधाई
+टेक्नोलॉजी
+थाई
+मापने
+सोशल
+७५
+फॉण्ट
+चित्रकूट
+प्राइवेट
+मराठा
+तुम्हारा
+जमशेदपुर
+१९६१
+सावली
+भूमिकाओं
+चयापचय
+अभिन्न
+किन
+खंडों
+एलिजाबेथ
+ग्रहणाधिकार
+ताजा
+निक
+उदा
+प्रयोजनों
+पश्चात्‌
+लेखो
+गन
+नमस्ते
+जोनाथन
+गोविंद
+ऑटोमोबाइल
+गोलाकार
+गंभीरता
+फिनलैंड
+प्रबन्धन
+पूर्णविराम
+एलेक्स
+मनोहर
+सौदा
+स्टाइल
+२०१२
+पीट
+सामरिक
+रेड्डी
+दया
+प्रा
+वॉल्ट
+वादा
+दरों
+उपन्यासकार
+तरंगों
+स्पैनिश
+बरेली
+दोस्ती
+विकारों
+पंक्तियों
+दिखायी
+ड्रैगन
+चाँदी
+यश
+विकृति
+बेसिक
+कामयाब
+हल्की
+अंडा
+वास
+आर्मी
+कार्तिक
+श्रे
+ब्रह्मचारी
+अर्द्ध
+ग्रेड
+फिल्मांकन
+पूर्वानुमान
+साइटों
+मैत्री
+इज
+कलाओं
+मुद्रित
+मिलर
+सुंदरता
+युवाओं
+विंबलडन
+मीले
+पाणिनि
+सहारनपुर
+पिशाच
+केंडीबार
+मृ
+डिवीजन
+निकलकर
+निभाया
+मनी
+वक्ता
+सिग्नल
+कैलाश
+वाक्यांश
+तुर्क
+विशेषण
+निशाना
+अग्रसर
+रैंक
+१९५०
+खाद
+ङ
+सीटों
+कनेक्शन
+पेट्रोल
+तु
+ग्राफ
+रण
+कंट्रोल
+रत
+जुड़वां
+पूर्वक
+बर्बरता
+पेरू
+एहसास
+व्याख्यान
+गिल्ड
+न्यूज़ीलैंड
+कमान
+पुत्रों
+फ्रांसिस
+पुजारी
+भरतपुर
+कुवैत
+मापा
+खाई
+थकान
+रिक्त
+अनुमोदन
+लेडी
+बाएँ
+शोथ
+अभिप्राय
+युवक
+स्टेम
+नीलम
+पीरपैंती
+प्रतियां
+बहाव
+बहार
+उत्
+अरविन्द
+आराधना
+मंगोलिया
+ध्वन्यात्मक
+फ़ेडरर
+एयरपोर्ट
+बाबर
+टेरियर
+क्रमिक
+विषम
+१९९३
+चालित
+स्थाई
+शीतल
+सज़ा
+अनुपस्थिति
+बफ़ेलो
+होस्ट
+क्लान
+जाएंगे
+ऊर्ध्वाधर
+द्रौपदी
+सूप
+रुपया
+१९४८
+मीना
+शेक्सपियर
+बेकार
+टैगोर
+किताबें
+प्रविष्ट
+सौंपा
+चा
+हिंदुओं
+ऑब्जेक्ट
+अवशोषित
+सातवीं
+पिन
+अयस्क
+हाइकु
+संस्थाएं
+निकासी
+भीषण
+सल्फेट
+बीघा
+निपटने
+नाते
+बाला
+रिक
+समलैंगिक
+आपातकालीन
+उष्ण
+ईस्टवुड
+रचनाएं
+बरसात
+अमित
+यजुर्वेद
+प्रशा
+संपदा
+व्यंजनों
+रॉकेट
+चट्टान
+जार्ज
+यहूदियों
+विजयनगर
+अल्फा
+उत्तेजना
+प्रायोगिक
+अर्थों
+गेज
+दस्तावेज़
+मानकीकरण
+१९७७
+पैक
+टेरी
+उल्लिखित
+काच
+परास्त
+स्वीकार्य
+रचनाकार
+अलंकृत
+शपथ
+अंगूर
+अग्रिम
+वंचित
+कपास
+पाण्डवों
+दानापुर
+घोर
+कामना
+बह
+धोखा
+नं
+प्रतियोगी
+१९६७
+ज़्यादातर
+जला
+अनुशासन
+मसाला
+अंडरटेकर
+दूरस्थ
+सेठी
+उसमे
+दिलाने
+मुक्केबाजी
+संस्कृतनिष्ठ
+ग्रा
+कोकेन
+जेरिको
+ठंडे
+प्रोडक्शन
+गर्ल
+विराट
+गेंदबाजी
+पैन
+जज
+कराची
+महानगरीय
+स्टाफ
+मजदूरों
+एनीमेशन
+शाखाएँ
+वाइन
+१९५६
+एंव
+वीर्य
+सकते।
+तलाई
+परिपक्व
+डेल
+अवस्थाओं
+सर्प
+उन्मुख
+भूभाग
+युद्धों
+रूढ़िवादी
+नाथनगर
+नामके
+लॉस्ट
+कॉट
+नियामक
+वहन
+कलम
+सम्राट्
+परिपूर्ण
+इश्क
+ड्रीम
+कब्र
+मोम
+अल्बर्ट
+दूरबीन
+उदर
+कानूनों
+जवान
+इन्हे
+सौदे
+गान
+दामोदर
+बेलारूस
+श्रेण
+दिख
+दही
+विजयी
+घोल
+चालीस
+मध्ययुगीन
+पेंगुइन
+समायोजित
+मिनी
+पीसी
+फ़्रांसीसी
+सीईओ
+भजन
+आदत
+लिखकर
+१९६८
+परमेश्वर
+एरिया
+कमर
+रेशम
+मिसाइल
+जेन
+मोटर्स
+उग्र
+शैव
+डालता
+यूनिवर्सल
+पिनांग
+फ्लैश
+विजेताओं
+१९८८
+स्वरों
+बैंगनी
+स्विच
+फेफड़ों
+सच्चाई
+चरित
+निकटवर्ती
+इंद्र
+निवेशक
+सिकंदराबाद
+पूंछ
+समाहित
+चित्त
+फिट
+खुसरो
+सार्वभौमिक
+खाया
+स्थानिक
+चिट्ठा
+लग्गा
+समझे
+उपसर्ग
+भोग
+साइन
+क्रीम
+पाकर
+बोलियों
+सका।
+१९७३
+सिद्धि
+गुलज़ार
+आलोचनात्मक
+मिलाया
+शोभा
+ऐनी
+दायरे
+गईं।
+जाएगी।
+वाल्व
+वैली
+रामचंद्र
+संध्या
+क्रय
+सम्बद्ध
+जमाने
+सहस्रनामन
+ध्वस्त
+किरणों
+कै
+आएगा
+एस्टन
+सोचना
+अनुयायियों
+जवाहर
+मॅट
+निभाने
+का।
+क्रोएशिया
+कीर्ति
+कल्चर
+चालु
+ईथेन
+इरादा
+न्यास
+वृंदावन
+हिम
+गेट्स
+ज़ी
+वृद्धी
+परीचय
+डेबिट
+कार्निवल
+सकी
+नालंदा
+यो
+परेश
+कालांतर
+मुखिया
+डेड
+डब्लू
+सांख्य
+फ्रैंकफर्ट
+अजीब
+वृत्ति
+एफ़
+अबतक
+रूट
+हिस्सेदारी
+आवेश
+रू
+अंतरण
+वॉकर
+भवानी
+पत्ती
+धवन
+लाभकारी
+मैगज़ीन
+ओपेरा
+निकलते
+परिधि
+विलक्षण
+बताती
+शिक्षित
+१९५४
+विद
+लेफ्टिनेंट
+उल्लेखनीयता
+जोली
+रतन
+डालर
+उड़िया
+अनुपालन
+क्रिस्टोफर
+केदारनाथ
+डायोड
+तराई
+गुरारू
+प्रतिपादित
+धुरी
+प्रतिबिंबित
+अंग्रेज़
+स्टेज
+खलनायक
+सुप्रीम
+राष्ट्रवादी
+स्विस
+कैथरीन
+अपोल्लोन
+हिल्स
+प्रवर्तक
+रबर
+जोड़ों
+बॉम्बे
+विवादों
+वेस्टर्न
+मध्यवर्ती
+मालिश
+दीवाना
+गुरुवार
+दर्शाती
+गतिविधियां
+मुख्यधारा
+ऋषियों
+खिलाडी
+औसतन
+फ्रेडरिक
+पंचम
+सूखी
+चौड़ा
+विधियाँ
+१९८७
+बेंजामिन
+गली
+हफ्ते
+डीप
+नलिका
+पिंक
+आईपी
+साउंडट्रैक
+दिनकर
+एमटीवी
+अंकन
+क्रूज़
+कैफीन
+बल्लेबाजी
+देसाई
+ऑप्टिकल
+विद्वान्
+हेड
+लेंगे।
+शिवा
+बॉण्ड
+कुशलता
+क्वांटम
+अनिश्चित
+कन्नड
+विचित्र
+रग्बी
+रिव्यू
+प्रपत्र
+निष्पक्षता
+आर्कटिक
+समस्याएँ
+प्रयोगात्मक
+जुडना
+वाल
+ज़िम्बाब्वे
+तलाक
+व्योम
+बिक्रम
+अमीनो
+प्रतिस्पर्धी
+श्रीश
+विश्वव्यापी
+ग्राउंड
+पॉवर
+्ड
+बहुतायत
+मौसमी
+उतर
+तैनात
+चित्रकारी
+इंटरफ़ेस
+खगोलशास्त्र
+गुहा
+अपराधों
+पाउडर
+नॉन
+टिप्पणियां
+डू
+राजन
+मेघालय
+समृद्धि
+सीमेंट
+कथाकार
+गौराडीह
+कतिपय
+डगलस
+असमिया
+आदिम
+हज़ारों
+मीर
+हड़ताल
+ज्ञानसे
+पोर्टलैंड
+्रेणी
+संकाय
+दर्शाने
+अल्लाह
+बिल्ली
+श्रमिकों
+अल्पसंख्यक
+मेजबानी
+चाइना
+ह्रास
+फ़ाइलें
+गल्फ
+राख
+औषधियों
+१८५७
+आश्चर्यजनक
+हाउ
+खेतों
+विनंत्ती
+बढ़े
+ग्रीवा
+ऋषिकेश
+पुनपुन
+जटिलता
+राज्‍य
+लक्ष्यों
+डमी
+किताबों
+जोश
+लड़कों
+कॉमिक
+कैमरून
+पूर
+हमे
+१९८१
+स्पर्धा
+दिखाता
+कार्यकर्ताओं
+वरदान
+कराई
+अनुकूलित
+आचार
+गार्ड
+सुर
+मोर्चा
+१९७४
+प्रदत्त
+प्रेत
+डेवलपमेंट
+कार्यात्मक
+बालू
+पहचानने
+आश्रित
+रॉबिन
+आकस्मिक
+कस्बा
+मालिकों
+उपाध्यक्ष
+सिलिकॉन
+करेगा।
+दूत
+संग्रहण
+ड्रग
+गिरजाघर
+मोहब्बत
+घूम
+चैन
+आर्यों
+महासचिव
+फिलहाल
+मेजबान
+बसने
+१९८३
+पोत
+एप्पल
+रेणी
+मल्होत्रा
+चैप्लिन
+जीवाणुओं
+१९७६
+छाती
+ट्विटर
+सिकन्दर
+बोझ
+बैठकर
+ऐसें
+विस्फोटक
+अद्वैत
+जीवनकाल
+विचलन
+कैपिटल
+नाटककार
+उपवास
+बसें
+बांटा
+मदर
+डेस्कटॉप
+उन्मूलन
+देनी
+इच्छुक
+नेटस्केप
+बैरी
+ढाका
+ति
+तह
+एचटीएम
+खुफिया
+कामों
+आतंरिक
+सोनिया
+स्वम्
+ईमान
+सार्थक
+मेडिसिन
+काण्ड
+कॉमन्स
+अफ़ग़ानिस्तान
+शिशुओं
+शतरंज
+१२४
+गाजियाबाद
+सर्दी
+स्क्रिप्ट
+बैकअप
+छद्म
+केली
+मकर
+साधक
+मूर्तियां
+शिया
+सूरी
+छाल
+अब्राहम
+फूड
+ञ
+पालि
+मीमांसा
+मीरा
+मान्यताओं
+कैसा
+विनय
+जाय।
+लेम्बोर्गिनी
+इज़रायल
+जीनोम
+मैक्सिको
+एलिज़ाबेथ
+नॉट
+कंक्रीट
+बाधित
+यूनिक्स
+पाण्डव
+स्तनधारी
+सिवाय
+शारदा
+सत्याग्रह
+पूर्णत
+कठ
+बताई
+लीड
+उत्सर्जित
+सुधारों
+एंडरसन
+उत्कर्षराज
+कमला
+मैनेजर
+डीजल
+डेक
+शेखर
+साईट
+संयम
+बढ़ाकर
+तैत्तिरीय
+चमत्कार
+कवच
+तिल
+सप्रू
+४००
+सिंधु
+सब्जी
+पाइप
+मैथ्यू
+लेग
+वादी
+काय
+नेचर
+कागज़
+मंजिल
+बेल्ट
+प्रोफ़ाइल
+गाथा
+सीमांत
+कीमतों
+अंतर्निहित
+मुद्राओं
+जग
+ममता
+स्टीवन
+शास्त्रों
+फोरम
+लिए।
+विचारक
+प्रबंधकोंने
+हिंदुस्तान
+सिखों
+महत्ता
+गोदावरी
+खुदाबंदपुर
+दुबे
+सबका
+फिक्शन
+व्यवसायिक
+मरे
+चमड़े
+कालोनी
+सितारों
+दुरउपयोग
+आयुक्त
+नसीरुद्दीन
+दाँत
+सुलतानगंज
+राष्ट्रिय
+फतुहा
+संग्रामपुर
+सोर्स
+करेंगे।
+सहयोगियों
+क्लैप्टन
+बीजगणित
+प्रांतों
+आभासी
+दीवान
+मानो
+गौण
+लगाता
+डेनिस
+सुदृढ़
+एडम
+आभास
+सदस्योंके
+उठता
+ल्योन
+बंगला
+टुन
+लिट्टे
+नक्काशी
+बिंदुओं
+हेपेटाइटिस
+वामन
+जिलाधिकारी
+्व
+आठवीं
+फी
+जिन्ना
+क्वार्टर
+अनवर
+विंडोज़
+देखरेख
+ऑयल
+समजकर
+साहित्यकारों
+बालकाण्ड
+कौटिल्य
+जामनगर
+अंचल
+बिकने
+ज्ञानकोषकी
+अंगूठी
+खींच
+एफबीआई
+पेस्ट
+विडियो
+मिलना
+लाइनों
+भूटान
+ट्रेडमार्क
+तने
+बापकी
+अत्याचार
+मॉरिसन
+मलय
+उतने
+एंटीबॉडी
+मिठाई
+१९७९
+कोलेस्ट्रॉल
+ेणी
+संतुष्ट
+बेगम
+समझता
+पोलिश
+फ़ुटबॉल
+मीटाकर
+तारापुर
+धनबाद
+एयरलाइन
+लाकर
+अप्रत्यक्ष
+इंकार
+लौटे
+मानसून
+रॉबर्ट्स
+फोर्स
+चलाते
+प्रिंट
+ठ
+यूनेस्को
+धुन
+स्टॉप
+हर्ष
+ऊ
+सावित्री
+सलाम
+फेडरल
+जनित
+कु
+अन्तरिक्ष
+विक्टर
+इथियोपिया
+दुरुपयोग
+भारद्वाज
+नमः
+दांते
+शव
+सचमुच
+मुनिता
+चौथाई
+सालाना
+कब्जे
+ओड़िशा
+अंतत
+संगमरमर
+पारिस्थितिक
+आरम्भिक
+राघव
+मैसाचुसेट्स
+वीकीपीडीयांके
+पुनर्जागरण
+मिलक्त
+बमबारी
+अस्थिर
+प्रतीकों
+उच्चतर
+पतले
+अधिकांशतः
+चरित्रों
+सौन्दर्य
+पुरातन
+डिज्नी
+ड्यूक
+कार्यालयों
+कमज़ोर
+मेट
+शेफ़ील्ड
+आरएनए
+उत्प्रेरक
+सेक्शन
+संभोग
+बास
+वापिस
+राष्ट्रभाषा
+सस्ते
+मैदानी
+लग्न
+भोजपुर
+कुण्ड
+सघन
+फ़ॉर
+१९६४
+संस्मरण
+फॉर्म
+वैद्युत
+पाम
+परदे
+अचल
+ग़लती
+मंद
+बरियारपुर
+शुद्धता
+परवेज़
+बॉय
+जीभ
+रोलिंग
+बदलना
+स्टब
+भुवनेश्वर
+कोइ
+हस्तांतरण
+मुकदमे
+फैलने
+पैरिस
+प्रत्यारोपण
+अफ़्ग़ानिस्तान
+दयाल
+कवक
+मेमोरियल
+एयरबस
+इंटेल
+फिल्मफेयर
+बरोबर
+पहुँचे
+सावरकर
+कुरान
+माली
+दिखाते
+किनारों
+निचली
+कराती
+किस्मों
+रहेंगे
+रीढ़
+खजुराहो
+शियर्र
+घात
+स्वयंसेवक
+मेगावाट
+झरने
+बाढ
+ग्रीष्म
+हराकर
+ठंडी
+गेहूं
+ओबेरॉय
+फ्रेंकलिन
+केंद्रों
+शुक्राणु
+रूपये
+इकाइयां
+हटाकर
+प्रचारक
+रैंकिंग
+नीली
+क्लाउड
+निजामुद्दीन
+फर्क
+ग्लास
+उपजाऊ
+गैरी
+घुटने
+सत्यजित
+न्यून
+कमजोरी
+जोएल
+हरीश
+जन्मदिन
+क्योकि
+शिवराज
+ख़़ुदा
+सिक्कों
+पंचांग
+मिथिला
+१९३०
+पेशे
+राष्‍ट्रीय
+पहना
+कॅरियर
+प्रतिष्ठान
+मालदीव
+कलाम
+गेहूँ
+हुयी
+दुष्ट
+रांची
+टुकड़ा
+डाकू
+प्रक्रियाएं
+सहाय
+फ्रंट
+निकास
+लहसुन
+हेलन
+डाइऑक्साइड
+श्रद्धांजलि
+चिप
+रोमांटिक
+बॉडी
+शोक
+सितारा
+लेनी
+आयुर्विज्ञान
+फेम
+हरित
+हीमोग्लोबिन
+ब्रायंट
+गोला
+मानद
+कब्ज़ा
+व्यू
+प्रदर्शनों
+डेमोक्रेटिक
+फेंक
+आंत
+समुच्चय
+मातृभाषा
+महाराणा
+रिटर्न
+१९५७
+छपाई
+उपग्रहों
+गोले
+जीवंत
+रियो
+ैं
+दृढ़ता
+धीमा
+गज
+यादृच्छिक
+विपक्ष
+विमानन
+कथाएं
+चेष्टा
+गतिशीलता
+लालकुआँ
+१५०
+दिलचस्प
+बैक्टीरिया
+पवार
+ढांचा
+पंप
+नूतन
+आमन्त्रित
+पुस्तिका
+चौदह
+फोर
+सऊदी
+सरसों
+कैलिफ़ोर्निया
+नेल्सन
+रकम
+६५
+कहा।
+नायिका
+आभार
+अनजाने
+एस्टर
+एलेन
+प्रेरक
+जरुरी
+वाइल्ड
+विशेषाधिकार
+नरसिंह
+ब्रदर
+अधिकता
+बर्मी
+धाराओं
+सिंघल
+समीक्षकों
+राजदूत
+समारोहों
+ढेर
+सूखा
+अर्जेन्टीना
+प्लेटो
+१९६३
+१९६६
+स्थलाकृति
+इरादे
+कर्मों
+जानेवाली
+क्षीण
+मरुस्थल
+प्रांतीय
+स्काई
+ऍ
+विशिष्टता
+एमी
+अरबों
+इंसुलिन
+युवावस्था
+कैमरे
+नमूनों
+जावेद
+नक्शे
+सु
+१९६९
+संकुचन
+किय
+समीक्षाएं
+स्पिन
+हवाला
+कारावास
+शिक्षकों
+नाहीं
+सर्जन
+दाने
+उठाते
+वरन्
+६००
+उठाना
+भट्टाचार्य
+्ता
+डोनाल्ड
+संतृप्त
+हड्डियों
+मिलाने
+करनेवाला
+निकोबार
+दे।
+सॉसेज
+चेतन
+त्रिवेंद्रम
+ऐन
+करीबी
+मासको
+पहेली
+देशभर
+इमेज
+मोटाई
+सिगार
+ऑक्सीकरण
+मैनुअल
+सूअर
+चलना
+पड़े।
+पर।
+पराजय
+मंगेशकर
+नर्तकी
+यज्ञोपवीत
+देखिए
+द्योतक
+आतां
+मीठे
+भागने
+रूपी
+परिणत
+श्रृंगार
+शक्तिपीठ
+कुरु
+बीजिंग
+मुगलों
+घटा
+सच्चा
+वान
+पैकेट
+चौथान
+मॉर्गन
+सिवा
+इन्टरनेट
+वैधानिक
+मास्को
+भेड़
+रोहिणी
+मैरीलैंड
+भेजी
+मिर्ज़ा
+परिशिष्ट
+निर्माणाधीन
+असे
+रॉन
+डायरी
+द्
+संदूक
+नक्शा
+विराजमान
+विकल्पों
+प्रधानता
+लिपियों
+काउण्टी
+याचिका
+वरीयता
+विजू
+त्रुटियों
+निर्देशिका
+चूर्ण
+समूचे
+प्लस
+टाइपिंग
+लिखें
+दोहरे
+प्रथाओं
+निर्मल
+रस्सी
+बेखम
+ण्ड
+बजाया
+मुलायम
+हमीरपुर
+बंधक
+प्रतिरक्षी
+आपरेशन
+निसान
+नरम
+वॉल्यूम
+ख्याल
+क्रैमलिन
+इट्स
+थ्योरी
+शेयरधारकों
+सुमीत
+अंदरूनी
+लवी
+माधुरी
+खातों
+गाड़ियों
+सजावट
+निपटान
+खोलकर
+जन्मा
+पीएच
+अभिनेताओं
+चावला
+प्रेमिका
+स्विट्जरलैंड
+ब्राउजर
+मोदी
+शेरशाह
+नमी
+चालुक्य
+सूफी
+उचाई
+कोलम्बिया
+सू
+उठाकर
+ग़ज़ल
+क्षरण
+ग़लत
+खरीदारी
+दुल्हन
+शम्मी
+निष्ठा
+प्रविष्टि
+साम्यवादी
+रहेगी
+अनोखा
+स्तुति
+उपलब्धियों
+परियोजनाएं
+गद्यकार
+स्विफ्ट
+इंडीज
+लौकिक
+कोशों
+प्रिया
+शिष्यों
+निकली
+बाँटने
+टकराव
+मौजूदगी
+निरन्तर
+आकाशवाणी
+उल
+चीफ
+सुविधाजनक
+यादगार
+समाचारपत्र
+म्युज़िक
+सूचनाओं
+जमालपुर
+रोकता
+लक्षित
+दौलत
+स्पेंसर
+लालू
+पिच
+आसवन
+ज्वार
+पाषाण
+संयोजित
+अरे
+ईथरनेट
+मय
+आखिरकार
+एथेंस
+लड़का
+धूम
+निर्देशों
+आहे
+प्रयोगकर्ता
+झीलों
+ज्वाला
+नागालैंड
+आपत्ति
+कांस्य
+ख़राब
+करनेवाली
+विगत
+ार्ता
+फेडरेशन
+वैसी
+युनुस
+वस्त्रों
+श्रद्धालु
+अदृश्य
+सामर्थ्य
+६३
+हार्दिक
+मानदंड
+बौना
+सुनवाई
+शॉपिंग
+बराबरी
+सि
+पलायन
+लाइसेंसिंग
+अञ्चल
+जगदीप
+गोत्र
+देहांत
+कार्टर
+प्रतिबन्ध
+शैतान
+फांसी
+रीड
+बोतल
+गोविन्दा
+सामंजस्य
+फर्श
+फिल
+यूएसए
+गाते
+उपक्षेत्र
+एंग्लो
+तुमने
+बुगु
+निर्वाह
+बताए
+दूरदर्शी
+धोखाधड़ी
+संचालक
+तकरीबन
+आमिर
+स्टारबक्स
+जड़ें
+रूम
+टेल
+घोड़ों
+नरसंहार
+प्रीति
+अश्लील
+कलश
+कैलगरी
+८५
+घूमते
+प्रवक्ता
+वूल्वरिन
+अप्रत्याशित
+आंकड़ा
+ग्रीनहाउस
+फेस्टिवल
+अनूदित
+सर्वे
+चेन
+छवियों
+अधिकाधिक
+मिटा
+पिरामिड
+अग्र
+चाणक्य
+प्रक्षेपास्त्र
+१९७८
+विक
+टंडन
+मैनहटन
+कैच
+मौन
+टमाटर
+सांद्रता
+इस्तीफा
+करवाने
+समीक्षक
+फारस
+वज़न
+प्रवृत्तियों
+लुइस
+उत्तीर्ण
+राँची
+वनस्पतियों
+अल्फ़ा
+रीडर
+गेंदबाज
+नकद
+क्रिश्चियन
+राजेंद्र
+ऐल्कोहॉल
+कच्चा
+असोसिएशन
+लैंग्वेज
+मसाले
+ज़रूर
+मंडी
+सुमन
+सनी
+कर्मियों
+साइबेरिया
+कंपन
+आवर्त
+रुधिर
+गढ़ी
+चिकन
+स्नेह
+दत्ता
+धर्मग्रन्थ
+जौनपुर
+मुरादाबाद
+पर्वतमाला
+लौटा
+लाये
+गोपी
+दाएं
+पुनर्जीवित
+आगम
+प्रतिक्रियाओं
+हीरे
+तीर
+भ्रष्ट
+गर्भाधान
+परेड
+टेलीग्राफ
+ऐक्शन
+वीरता
+आर्क
+इफ़्तेख़ार
+टार्ज़न
+प्रतिलिपि
+डेढ़
+सम्पत्ति
+गर्व
+मदुगु
+माघ
+मूर्तियाँ
+छन्द
+कठिनाइयों
+अभियानों
+तया
+चांद
+कौषीतकि
+वास्तुकार
+पडता
+मज़बूत
+कार्यान्वित
+क्लाइंट
+पूरब
+साइमन
+क्षतिपूर्ति
+माध्यमों
+स्केल
+उत्तरदायित्व
+पतला
+पीटर्सबर्ग
+नौका
+पटल
+समझाने
+मिसौरी
+आण्विक
+एस्पिरिन
+म०ब०
+जोन
+कुक
+बाईं
+ध्येय
+ब्लेड
+कृत्य
+गार्सिया
+तीर्थंकर
+सम्मुख
+चाहीये
+मार्केटिंग
+रोमांचक
+सहानुभूति
+वायरलेस
+घृणा
+महाद्वीपीय
+उर्मिला
+बसंत
+दवाएं
+पकाने
+नन्दा
+अलवर
+निराशा
+छिपा
+तपेदिक
+आदिवासियों
+अनुवादित
+सातवें
+सिक्का
+संवत्
+सावन
+कार्पोरेशन
+उर्वरक
+राही
+ओलिवर
+पांचवें
+झीलें
+डेविल
+खां
+अन्तरराष्ट्रीय
+ब्राह्मी
+कांड
+जू
+गाँवों
+भैरव
+वीकली
+टुडे
+बेसिन
+बाघों
+निरूपित
+शाप
+मन्त्री
+कुंडली
+अथ
+राष्ट्रगान
+आणविक
+दांतों
+वैश्वीकरण
+कहें
+शैवाल
+सिलसिला
+कैरी
+१९५५
+काबुल
+मोटरसाइकिल
+विवश
+फ़ूड
+अरोड़ा
+गिरोह
+पते
+झरना
+अनुमोदित
+मांडूक्य
+कडियां
+मजाक
+जरी
+विकीपीडिया
+होत
+जमैका
+स्पष्टीकरण
+पाद
+जरूरतों
+एम्पायर
+हस्त
+संहिताओं
+लड्डू
+मध्यकाल
+वीकी
+देवगन
+चित्रआकार
+विदिशा
+कॉफ़ी
+सेंचुरी
+होते।
+मित्रता
+कठोरता
+वज़ीर
+रूपक
+अश्वेत
+राज्यसभा
+आभूषण
+चैम्पियन
+उपरान्त
+लार्ड
+नोबल
+प्रविष्टियां
+बस्तियों
+िए
+नानक
+बर्ड
+पड़ेगा
+लिंकन
+बहाल
+९६
+बंदूक
+रेट
+अयोध्याकाण्ड
+महाप्रभु
+ग्राहम
+नल
+डार्विन
+ग्रेटर
+कारखानों
+वाट
+सोचने
+हिम्मत
+बढाने
+लेबर
+गिना
+पूर्वजों
+बेचे
+हरिवंश
+श्वेताश्वतर
+माइक्रो
+सीनेट
+पु
+दिए।
+नकदी
+ब्रॉडबैंड
+फ्रेमवर्क
+दाग
+ँ
+ग्लूकोज
+आश्वासन
+दरगाह
+बीवी
+किस्में
+अभिकल्पना
+इन्दिरा
+रामकृष्ण
+शेन
+वार्
+पॉइंट
+झांसी
+चेल्सी
+वाइस
+महानतम
+विश्वसनीयता
+चूना
+डिस्प्ले
+प्रकोप
+सदाबहार
+लोहिया
+मीनाक्षी
+र्ता
+हावर्ड
+इस्लामिक
+कौशिक
+भुजा
+पहलवान
+जादुई
+अर्थशास्त्री
+मनमौजी
+शायर
+डिजाइनर
+समयावधि
+सपनों
+मर्यादा
+रेकी
+दरवाजा
+उत्त
+बारूद
+हे।
+कुर्सी
+जन्मजात
+लूट
+नियोजित
+नियोजन
+तेरह
+हिंगू
+मैडोना
+्म
+सोमनाथ
+पीपुल्स
+मुद्रास्फीति
+बजाने
+काँच
+तैराकी
+साबुन
+अभ्यारण्य
+बढ़ाते
+तन
+उ०प०
+महासभा
+अहंकार
+मांसपेशी
+निर्वात
+खतरों
+जाओ
+हैपलोग्रुप
+हैवीवेट
+आरोपों
+सितारे
+विनियमित
+सब्जियों
+शीतकालीन
+पार्टियों
+शिला
+रसवात्सल्य
+पश्च
+चॅक
+लड़ाकू
+तुझे
+रॉस
+क्लोरीन
+विषाक्तता
+मानों
+वाक्यों
+प्रतियों
+उल्टी
+हैरिस
+निकालना
+अक्षम
+सिंधी
+विशेषत
+आस्ट्रिया
+अवगत
+साधारणत
+मार्क्स
+चीता
+व्यवसायों
+डालना
+क्षितिज
+पालिका
+उल्टा
+कारखाना
+सैयद
+कमेटी
+भला
+फेयर
+फ्लू
+रामभद्राचार्य
+स्प्रिंगस्टीन
+पिस्टन
+संदर्भों
+जनसँख्या
+आनुवांशिक
+उषा
+ज़रिए
+सीमाएं
+घर्षण
+प्रौद्योगिकियों
+दिखती
+मतों
+लत
+बैले
+एक्यूपंक्चर
+फोटोग्राफर
+क्रिकेटर
+अनीता
+इण्डिक
+आधिपत्य
+सतही
+गुफाओं
+प्रतीकात्मक
+नशीली
+शुक्ला
+शेंगेन
+फास्ट
+बुल्गारिया
+महंगे
+सनम
+नज़रिया
+हेलो
+माथुर
+सेवाएँ
+रिपब्लिक
+सेंसर
+सर्कल
+बिज़नेस
+सेकेंड
+असत्यापित
+कैनेडी
+दुर्भाग्य
+विनायक
+कारगर
+प्रस्तावना
+अरस्तू
+बताये
+गृहयुद्ध
+तर
+शीट
+गिरफ्तारी
+वार्मिंग
+इसीलिये
+महासागरीय
+खनिजों
+पेरी
+जटिलताओं
+जीती
+लॉरेंस
+पूर्
+साठ
+सूडान
+एबीसी
+संस्थाएँ
+सिएटल
+आख्यान
+बोल्ट
+खानों
+यीशु
+परिलक्षित
+अभिमन्यु
+दैत्य
+पॉलिन
+निकाली
+राष्ट्रवाद
+खोजा
+साक्षी
+पारदर्शी
+७२
+जाएँगे।
+फुलवारीशरीफ़
+वैवाहिक
+जुलती
+सेंटीमीटर
+ईश
+नाभि
+रेशे
+संकीर्ण
+नेताजी
+टीके
+एड्रेस
+विश्‍व
+चार्टर
+बीना
+मधुबनी
+पियानो
+हेक्टेयर
+मंगलौर
+फलत
+सीने
+संभाल
+अलास्का
+स्पाइवेयर
+सुलोचना
+नीलगिरी
+तैसें
+उभरा
+राजकोट
+मिलीग्राम
+फाइलें
+हिब्रू
+बैग
+आटा
+होतीं
+शंख
+मजबूती
+सीना
+उनमे
+आज़मी
+अभिलेखों
+रोचेस्टर
+पुष्ट
+दाहिनी
+क़रीब
+कार्लोस
+जादूगर
+मैनें
+अवरुद्ध
+झ
+सस्ता
+लैंस
+टैक्स
+बैड
+इशारा
+पढ़ना
+विलायक
+ज्यामितीय
+एनी
+पत्तियाँ
+बहामास
+पढ़े
+कारें
+प्ले
+चश्मे
+प्रतिकृति
+झंडा
+उभरते
+स्टेनली
+डेव
+बेनोइट
+वीवरण
+निकालकर
+तदनुसार
+बुल
+अवशेषों
+कच्छ
+बताना
+एंटरटेनमेंट
+राज्यमंत्री
+मायने
+परख
+बराक
+मिले।
+ढाई
+प्रतिफल
+क्रियाएँ
+स्थूल
+बसु
+आकलनकर्ता
+गुट
+अथर्ववेद
+संस
+केट
+टीमें
+सैंडविच
+लेखिका
+कैबिनेट
+जुर्माना
+मारी
+मिटाने
+परवरदिगार
+अंदाज़
+मूल्यवान
+लिखता
+संचय
+साउंड
+युवराज
+विकिक्वेट
+स्कूली
+नशे
+प्रयोक्ताओं
+पापों
+पित्त
+बहल
+विकलांग
+डूब
+किंगफिशर
+कार्यक्षमता
+टेड
+वगैरह
+डाउनटाउन
+अपूर्व
+कलन
+थाली
+साढ़े
+पीली
+कृष्णन
+९९
+प्रोसेसर
+एमआईटी
+तंतु
+राजेन्द्रनाथ
+छीन
+स्टैंड
+मुरलीधरन
+कंप्यूटिंग
+सॉफ़्टवेयर
+चुप
+एसी
+प्रोटोटाइप
+चुनने
+राजी
+अंडर
+सुविधाएँ
+शरत
+हरेक
+मु
+विमानसेवा
+पड़ी।
+मूर्तिकला
+जुडी
+संविदा
+बाय
+बढ़ाता
+रुख
+लोकगीत
+समायोजन
+अमेरिकियों
+कैन
+जीप
+नक़ल
+तेथ
+श्रृंखलाओं
+ज़माने
+मशीनी
+एक्सरे
+आह्वान
+अलाउद्दीन
+प्रत्याशी
+बिन्दू
+रहस्यमय
+रेखाएँ
+पिया
+पत्रकारों
+प्रतिभूति
+उमर
+स्वच्छता
+घनश्याम
+विषाक्त
+दबाने
+अध
+जोड़ते
+वायुमंडलीय
+ठंड
+बर्फ़
+फीसदी
+लेआउट
+दरिया
+क्लबों
+छत्रपति
+असुरक्षित
+नागरकोविल
+कार्यो
+सौभाग्य
+परवाह
+महंगा
+युगांडा
+नवाचार
+रामचन्द्र
+जुलता
+निष्कासन
+गर्भगृह
+वेदांत
+निराश
+शोधकर्ता
+पड़ोस
+मौके
+असफलता
+गय
+जयसिंह
+हैदर
+संगीतकारों
+दीपावली
+मूसा
+समाजों
+मानवाधिकार
+जोड़ना
+ट्रम्प
+एंजाइम
+गांधीजी
+चुनी
+१९३१
+डिवाइस
+समझाया
+हजरत
+प्रमोद
+कुशीनगर
+बर्मन
+गोलार्ध
+मोह
+पढ़ते
+गवाह
+मर्सिडीज
+आमन्त्रण
+कतर
+एकाधिकार
+टायसन
+ऑपरेटर
+बलराम
+होंगी
+आये।
+नानी
+अलीगंज
+जहा
+विद्युतीय
+जड़ों
+अपराधियों
+द्वि
+जौ
+बंदर
+बढ़िया
+रेसलमेनिया
+इलेक्ट्रान
+फिलीपींस
+प्राप्‍त
+क्यूंकि
+विकलांगता
+जिल्हा
+सींग
+बछवारा
+हावी
+गाए
+एकेडमी
+वाइरस
+सवालों
+फोटोग्राफी
+हाइड्रोकार्बनों
+कोबेन
+स्वर्गीय
+यार
+कोशिकीय
+बखरी
+उतरने
+गैलापागोस
+विलास
+हंगल
+आज़ादी
+अंशों
+सिलेंडर
+केन्या
+अप्रयुक्त
+धर्मनिरपेक्ष
+प्रबंधको
+ताजिकिस्तान
+पुनर्गठन
+स्टडी
+समा
+ीर्षक
+दोषों
+आईएसओ
+कोला
+रेलमार्ग
+जहाज़
+बहाने
+थोक
+जानबूझकर
+बेकेट
+कमाने
+खाल
+छावनी
+डबल्स
+पहनते
+आल
+मनोरंजक
+फ्रैंकलिन
+भ्रमित
+सुज़ुकी
+वॉर्स
+वर्जित
+अनशन
+वुड
+अपवाह
+श्राफ
+एवेन्यू
+नाप
+पर्पल
+हुक्म
+भूगोलवेत्ता
+दबा
+उभर
+शंघाई
+पैकेजिंग
+नॉटिंघम
+वर्
+भूमिकाएं
+जनमत
+सीखा
+हलसी
+ग्रैमी
+सकेगा
+वार्त
+१९४०
+डैन
+कलंकीत
+कारन
+नहरें
+पडा
+२५०
+दर्रा
+ओड़िया
+कांफ्रेंस
+तिमाही
+फिल्टर
+ग्राफिक्स
+लाइक
+रोज़ेज़
+केक
+आंदोलनों
+ऑ
+७६
+गाँठ
+सेन्ट्रल
+करों
+पोजीशन
+ट्रांस
+अस्पतालों
+प्रचारित
+सपोर्ट
+समितियों
+एस्टेट
+संकुचित
+दिखते
+जलन
+उत्तराधिकार
+प्राध्यापक
+सूक्ष्मजैविकी
+मिर्जापुर
+रैखिक
+नैनोट्यूब
+वीजा
+गुजरती
+मालाबार
+निगमों
+पोरबंदर
+ट्वेंटी
+नवरातिलोवा
+्त
+७७
+जासूस
+अभूतपूर्व
+नवागन्तुकों
+वर्मनने
+मिसाल
+गरीबों
+फूट
+फ्रेंड्स
+फोकस
+शत
+तैसा
+गे
+एनिमेशन
+मेवाड़
+स्ट्रीम
+१९५८
+प्रमुखता
+पेशियों
+ऋ
+जलाशय
+चलाता
+क्ष
+हेमामालिनी
+बैंगलोर
+सुनते
+लैंगिक
+सुदर्शन
+रमन
+नाइट्राइट
+टिहरी
+कैदी
+कस्टम
+खरा
+चिप्स
+अनगिनत
+महाकवि
+आवश्यकताएं
+कमिश्नर
+रचा
+श्रेणीबद्ध
+रवाना
+बूटी
+वाँ
+खिलौना
+गर्ल्स
+कमांड
+चलाना
+संसद्
+तस्वीरों
+प्रतियोगिताएं
+शाखाएं
+निरूपा
+पावन
+रसायनों
+औषध
+वीणा
+साजिश
+बुजुर्ग
+एनालॉग
+मकबरे
+परीक्षित
+धोनी
+नबम्बर
+प्रबंधित
+सैल्मन
+आकारों
+सवाई
+माईस्पेस
+किण्वन
+आईबीएम
+प्लांट
+गुजर
+शर्ट
+ल०व०
+विकिसम्मेलन
+पंद्रहवीं
+मातृ
+ीय
+भिक्षु
+फ़ोटो
+अपडेट
+दोहरा
+क्रेन
+बाइबल
+पहुँचाने
+दाएँ
+निःशुल्क
+नाइट्रेट
+एरनाकुलम
+पहुंची
+सक्रियता
+लियोन
+मंडली
+लोकपाल
+निकायों
+आधुनिकता
+वसूली
+नारा
+राना
+गॉर्डन
+दांव
+चन्द्रशेखर
+हार्बर
+सलाद
+मंत्रिमंडल
+रसेल
+तब्दील
+आशिक
+विधायक
+बची
+१९४९
+जैकी
+पनीर
+वेशभूषा
+वेल्श
+पसन्द
+चुपके
+चि
+अतरी
+परतों
+मधुबाला
+सांप
+पहुंचता
+रोकना
+पकड़े
+१९२०
+पीतल
+नास्तिक
+नासिर
+किस्मत
+लाइनें
+प्रतिबिंब
+माफी
+मार्क्सवादी
+एथिलीन
+कोशीश
+जगद्गुरु
+जीना
+वाह
+प्रेसीडेंसी
+सीनियर
+पूर्णता
+फिजी
+अत्र
+होनेवाली
+बिड़ला
+रिवाज
+उपनगर
+ईथर
+बद्रीनाथ
+शीर
+ु
+रेखाचित्र
+महेन्द्र
+त्तराखण्ड
+सूत
+सीढ़ी
+भट्ठी
+भण्डार
+व्यवसायी
+सेवानिवृत्त
+गुणांक
+जामा
+शेखावत
+८००
+क्रूर
+घिरे
+फलक
+अम्बेडकर
+लगन
+बिन्दुओं
+मुकुट
+वेस्टमिंस्टर
+इमाम
+बर्नार्ड
+मृदा
+बायें
+शासकीय
+ख़िताब
+षड्यंत्र
+रेखीय
+स्पीयर्स
+जीमेल
+डिस्ट्रिक्ट
+अल्बानिया
+राशियों
+लीन
+गवाही
+जस्टिस
+स्पेलिंग
+बाँटा
+कुश
+मकसद
+अटल
+मेटा
+सर्पिल
+रास
+पंखों
+संवेदना
+हलचल
+संकल्पना
+३०००
+मक्खन
+जॉर्डन
+मिथ्या
+समीकरणों
+फेफड़े
+पैतृक
+प्लैटिनम
+एंथोनी
+वीनस
+बदली
+७००
+पीढ़ियों
+सूरीनाम
+स्ट्रॉस
+क्रियाशील
+विक्रेताओं
+मोल
+लड़ते
+रहो
+वक्तव्य
+उत्पादकता
+मॉनिटर
+पुरोहित
+मालवीय
+समझी
+रूपांतर
+पनामा
+प्रतिरोधक
+समस्तीपुर
+वेधशाला
+पीड़ितों
+देवदास
+अवधारणाओं
+फर्ग्यूसन
+ग्लेन
+चौड़े
+फाँसी
+आंत्र
+त्रि
+फेरारी
+पदार्थो
+शंकु
+दादी
+पुनरावर्तन
+विवरणों
+हलके
+दरार
+मीन
+गिरीश
+चुनें
+निभाता
+१९४५
+स्पीड
+यथार्थवादी
+तोप
+किट
+चिन
+पुकार
+मॉडर्न
+कड़े
+कावेरी
+आई।
+तूफ़ान
+द्योल
+पिकनिक
+बायर
+गिटारवादक
+एकांकी
+लगाव
+सस्ती
+खुदा
+बढ़ाना
+संयंत्रों
+निष्पक्ष
+अरविंद
+पकड़ा
+गिने
+शहद
+मिथक
+मून
+दीया।
+डेविडसन
+ग्राफिक
+प्रियस
+अनिष्पक्ष
+कराटे
+सुनहरा
+सचिवालय
+फ़ॉर्मैटिंग
+वाल्टर
+स्तंभों
+आटे
+स्मार्ट
+मेक
+घाटियों
+मेसन
+अनोखी
+सदाशिव
+प्रतिजन
+रुझान
+प्रवीण
+कपिल
+विधवा
+रुकावट
+टर्नर
+त्रिभुज
+मंत्रियों
+तत्पश्चात
+चूहे
+म्हणे
+कॉलेजों
+उत्कीर्ण
+र्षक
+घेर
+नेपोलियन
+सुलझाने
+विभिन्‍न
+आइस
+भित्ति
+गला
+वैधता
+लुकास
+उड़
+स्टैंडर्ड
+खिलौने
+युगों
+लिवरपूल
+लिप्यन्तरण
+खड़ीबोली
+पर्दे
+शत्रुघन
+अग्निहोत्री
+वर्चस्व
+बहिष्कार
+एडवेंचर
+यूटोपिया
+ऐसीटिलीन
+विचरण
+कल्पित
+मुख्‍य
+अपनाई
+गंधक
+ेश
+किशोरावस्था
+लेज़र
+कैम्प
+टाई
+तुरन्त
+अर्धचालक
+मॉरीशस
+साँस
+संगठनात्मक
+बहुवचन
+तले
+कभार
+पुकारा
+चाँदनी
+१९५९
+जिनपर
+नागराज
+मोनिका
+्तराखण्ड
+६४
+सुखद
+आवारा
+पानदारक
+एशियन
+चैत्र
+कैश
+हथेली
+नैनो
+झूठा
+विस्थापन
+प्रमाणीकरण
+इसराइल
+आठवें
+सागरीय
+प्रजापति
+किसने
+सभ्यताओं
+अर्ल
+स्वराज
+१९३६
+चन्द
+बसाया
+महानदी
+वर्ड
+रिसाव
+चम्मच
+प्रशिक्षक
+रघुनाथ
+एमिनेम
+सुधा
+पंद्रह
+काटा
+चादर
+जैम
+निकटता
+उमा
+भयभीत
+फ़ॉर्मूला
+शाहजहाँ
+इंजीनियरों
+वर्दी
+ूर्व
+आनुवंशिकी
+घेरा
+हाथियों
+रैली
+संलयन
+आवर्ती
+क्रियान्वित
+दशहरा
+वृद्ध
+विरोधियों
+बोवी
+भूविज्ञान
+पो
+होय
+ऋणात्मक
+लाते
+अण्डा
+सम्बंध
+बोट
+इटावा
+साहसिक
+आपातकाल
+टायर
+साइप्रस
+चूहों
+विधियां
+षक
+जोड़ती
+त्रिज्या
+मनाते
+बांड
+प्रतिबद्धता
+आइसलैंड
+उत्तेजक
+पैमाना
+बांद्रा
+गर्भपात
+पब्लिशिंग
+अन्यत्र
+बम्बई
+महीन
+पूंजीवाद
+क्रियान्वयन
+संगीतमय
+दैट
+दाखिला
+आवश्यकतानुसार
+मेनन
+स्प्रिंग
+ख़िलाफ़
+शक्तियां
+अंतरजाल
+यूक्रेन
+अस
+वर्जिन
+मानती
+सद्भावना
+आंद्रे
+वल्लभ
+इजरायल
+अध्यायों
+मजदूरी
+उत्तरोत्तर
+प्रभात
+श्रोताओं
+हलन्त
+हीरोज़
+कुँवर
+अलेक्जेंडर
+कराया।
+वोल्टता
+एवार्ड
+गोल्डेन
+पनडुब्बी
+स्टेरॉयड
+सचदेव
+ट्रू
+सिरों
+मारकर
+माउंटबेटन
+बार्नस्टार
+कोका
+मन्दिरों
+फ़िल्मी
+धाराएं
+सांप्रदायिक
+आत्मसमर्पण
+समांतर
+प्रीमियम
+विनोबा
+बहुराष्ट्रीय
+डैविल
+धागे
+दसवीं
+बार्कलेज
+बिरला
+प्रतिमान
+कक्षाओं
+हैना
+अमूर्त
+मंज़िल
+निरंतरता
+निपुण
+ढोल
+१९४२
+मनोरोग
+डेप
+यूनीवर्स
+डाला।
+क्षार
+शूट
+बेसबॉल
+बीएमडब्लू
+शौकिया
+प्रागैतिहासिक
+ारत
+मुझ
+गुफाएं
+वर्क
+अनन्य
+सुरुचि
+छा
+बग
+कर्क
+उठे
+हक
+प्रशस्ति
+कलाई
+जयप्रकाश
+महीना
+चिंतित
+दूषित
+नियोक्ता
+स्वदेश
+यत्र
+पूछताछ
+विस्थापित
+खोजों
+लाभान्वित
+कांट
+पहचाने
+बॉर्न
+प्रवृति
+रेजिमेंट
+थिंक
+ऐश
+स्थगित
+सीटी
+विशेषतः
+बुराई
+रुद्रप्रयाग
+सुषमा
+८४
+बनी।
+जनजातियों
+रेख
+अन्याय
+संवाददाता
+कच्ची
+बोलियाँ
+एडी
+पेंटिंग
+जिन्हे
+रति
+स्टार्च
+अबू
+पहुंचते
+अम्लीय
+सैर
+बीबी
+इंटरटेनमेंट
+वानस्पतिक
+बेशक
+श्लोकों
+आपात
+नन्द
+मेज
+तृतीयक
+टॉड
+प्रसिद्द
+रांगेय
+कैप्टन
+बीन
+चाह
+बनीं
+पोटेंशिअल
+असित
+सीरम
+कैदियों
+चुनरी
+ज्येष्ठ
+अगासी
+जस्ता
+थेरेपी
+मैथुन
+लोकल
+सूर
+यात्राओं
+गेंदों
+चढ़
+गाजीपुर
+भागीदार
+राहु
+सजाया
+उत्पीड़न
+ओमान
+बायीं
+तुर्कमेनिस्तान
+फेस
+धड़
+वन्यजीव
+चीज़ों
+अनमोल
+निभाते
+जैसें
+मुंशी
+सुपरमैन
+बहारी
+विकिस्रोत
+दुग्ध
+लगीं
+गुड्डी
+माउस
+आग़ा
+गोरखा
+कसौटी
+अल्फ्रेड
+पूज्य
+वोक्सवैगन
+ख़
+तना
+ट्रैफिक
+खंडित
+मो
+्षक
+नायडू
+शबाना
+आतंकवादियों
+जाली
+लिविंग
+पुनरावृत्ति
+एक्सप्लोरर
+फ़ोर्स
+श्रोता
+राजनयिक
+तुल्य
+डेज़
+फ्रेड
+परोसा
+ची
+फोर्ब्स
+कण्ठ
+बर
+कीन
+प्रतिभागियों
+सुरेन्द्र
+फाइलों
+निद्रा
+बंगलोर
+संभावनाओं
+बॉस्टन
+हार्ले
+प्रोसेसिंग
+नासिक
+वाइड
+एनर्जी
+पकवान
+दारा
+कम्पनियों
+थोडा
+नवादा
+सप्त
+शाहरुख़
+तांबे
+नग्न
+अंजाम
+तुग़लक़
+बचाया
+बैनर्जी
+बादलों
+संप्रेषण
+लैरी
+९८
+डायमंड
+शुभारंभ
+अपार
+देगा।
+खिड़की
+जश्न
+मैनपुरी
+विधाओं
+६६
+भ्रामक
+तंत्रों
+सीरिज़
+लहरों
+पुस्तकालयों
+विनाशकारी
+जैज़
+खतना
+बस्तियां
+उत्कर्ष
+कोशिकाएँ
+नेहरु
+मेड
+लिखा।
+धनात्मक
+चॉकलेट
+मनोरमा
+१९५२
+बार्सिलोना
+लावा
+फैजाबाद
+वाटर्स
+प्रात
+बढ
+विद्युत्‌
+मसलन
+मसूरी
+अचार
+सटीकता
+कीर्तिमान
+ब्रिगेड
+प्रकाशीय
+कं
+उत्साहित
+नौकर
+वारिस
+नामदेव
+हेमंत
+ईंटों
+इंटेलिजेंस
+सपाट
+गोबर
+पर्सनल
+कार्यप्रणाली
+असीम
+कॉलम
+झाँसी
+प्रबन्ध
+करिश्मा
+मिसिसिपी
+ब्रेकिंग
+निभा
+खाती
+दावों
+वोल्ट
+आप्रवासी
+धड़कन
+बिताया
+प्रशस्त
+बीटल
+महलों
+निलंबित
+एबरडीन
+लूथर
+बारबरा
+खण्डों
+यूज़र
+बर्बाद
+उन्नयन
+वेल्लोर
+राजबब्बर
+समन्वित
+लोप
+हल्दी
+बुद्धिमान
+किराए
+८८
+अनुसन्धान
+जेड
+बादाम
+पासपोर्ट
+खुलता
+माकपा
+प्रमाणन
+वृन्दावन
+सड़कें
+बम्बोर
+पोषित
+सिन्दूर
+अमोनिया
+श्रुति
+उठाए
+तकनीकें
+पदवी
+ऑर
+गड़बड़ी
+आमाशय
+नरक
+मुहैया
+गुजरने
+संग्रहीत
+जेसन
+सीक्रेट
+असिमोव
+कन्याकुमारी
+र्व
+झारखण्ड
+उत्तराख
+परिपक्वता
+८१
+कौरव
+ज्ञानकोश
+रंगोली
+गान्धी
+ध्वनियों
+कनाडाई
+छिपे
+म्हणोनि
+प्रणालियाँ
+विखंडन
+गुम्बद
+किक
+बख़्तियारपुर
+वश
+नैस्टर
+शा
+बर्गर
+फ़ल
+हुवा
+बिक
+अटलांटा
+रोधी
+बचना
+घा
+लुटेरे
+मेगाडेथ
+बीजों
+वियना
+चिन्तन
+अय्यर
+सोम
+चिन्हित
+रेफरी
+सहिष्णुता
+छोड़ना
+मसले
+उद्यमी
+जुलते
+स्लोवाकिया
+साख
+गोकुल
+दरबारी
+बढ़ाई
+देखा।
+खूबसूरती
+पैसेंजर
+फ्लाइट
+हवाओं
+पीढी
+नौगांव
+आगंतुक
+लिली
+उत्तरकाशी
+गुरुत्व
+सिखाया
+पियरे
+शीर्
+सिक्स
+डब्ल्यूडब्ल्यूएफ
+प्री
+दशमलव
+तेतिहा
+क़ानूनी
+धृतराष्ट्र
+हाजीपुर
+आर्यभट्ट
+प्रायोजक
+सन्दूक
+सांसारिक
+फलित
+नामका
+भट्टी
+पांव
+त्
+सम्पादित
+शोधन
+विश्‍वविद्यालय
+कंस
+पम्प
+चलाई
+करतीं
+ईपू
+मिज़ोरम
+हीन्दीवीकीपीडीयाके
+दायें
+अयोग्य
+मृग
+आनेवाले
+लीबिया
+लेसनर
+तुमको
+मेहमान
+मेलबोर्न
+स्‍थापना
+थर्ड
+इमेजिंग
+सम्मेलनों
+अमज़द
+लगेगा
+बेड़े
+इब्राहिम
+पक्का
+पलट
+मानदंडों
+त्रिनिदाद
+साम्राज्यवाद
+परीक्षक
+पड़ाव
+पहाडी
+जुड़ना
+विलोपन
+सिलसिले
+खींचने
+चलाए
+जानकर
+बेली
+विचारकों
+पितामह
+नॉर्मन
+डिपार्टमेंट
+स्वादिष्ट
+सुगंध
+पेस
+समता
+गोंडा
+लेस
+फैलाने
+सैनी
+पिज़्ज़ा
+रामधारी
+तांत्रिक
+साध्य
+जन्मभूमि
+संभालने
+आकृतियों
+अख्तर
+हेल
+तवी
+पांडवों
+मीलकर
+उत्खनन
+स्वैच्छिक
+दिल्‍ली
+श्रीलंकाई
+दोहराया
+मुखर
+टोयोटा
+रिपोर्टिंग
+निषिद्ध
+गंगोत्री
+डिक
+परमार
+बार्न
+फ़ैल
+इण्डोनेशिया
+अकादमिक
+ड्राफ्ट
+भूकम्प
+दिखलाई
+धर्मशास्त्र
+किये।
+क्राई
+बकरी
+पाया।
+न्यूर्क
+जौहर
+कामयाबी
+फौज
+सुव्यवस्थित
+डॉक्टरों
+बढ़त
+क्योटो
+दर्जन
+जुटाने
+कलर
+हिन
+ग्
+प्रेरण
+एथलेटिक्स
+कपाल
+जस्टिन
+पश्तो
+कुंभ
+थाइलैंड
+बांस
+ँव
+कनेक्टिकट
+जोरदार
+बेरोजगारी
+सुल्तानपुर
+बिस्तर
+खींचा
+प्रौढ़
+एल्बमों
+कड़ा
+मानकीकृत
+सामंत
+वृहत
+परबत्ता
+दुल्हिनबाजार
+सोल
+चना
+भोसले
+सप्ताहांत
+विशालकाय
+धोने
+भस्म
+रहनेवाले
+टेघरा
+अमीन
+फ़्रान्सीसी
+शल्यक्रिया
+ग्रांट
+१९२१
+सांकेतिक
+फार
+मदिरा
+पोर्शे
+परिधान
+यूरेनियम
+जिन्होने
+बलात्कार
+परीक्षाओं
+उत्तराखण
+ट्रेक
+जन्में
+पि
+पवित्रता
+इंतजार
+लाता
+वादन
+महत्‍वपूर्ण
+ब्
+अल्जीरिया
+सीखना
+नगण्य
+खत्री
+चतुर्भुज
+बाक़ी
+१९००
+टेन
+करोड़ों
+स्क्रीनिंग
+टूटने
+प्रजातियाँ
+आन्तरिक
+कहो
+अपघटन
+देशो
+ब्रेट
+पहुँचे।
+परिस्थितियां
+म्
+पुनर्निर्देशित
+नतीजा
+साइबर
+पैदावार
+स्याही
+नंदा
+सैटेलाइट
+न्यूट्रॉन
+रोनाल्ड
+देवेन
+चमकदार
+जिगर
+योजनाएं
+प्लेग
+अध्यात्म
+विदेशियों
+सच्ची
+चट्टोपाध्याय
+दार्शनिकों
+परिसंपत्ति
+ओक
+जाये।
+इलाक़े
+तुमसे
+बिखरे
+व्यवहारिक
+तराखण्ड
+मऊ
+प्लूटो
+दुखी
+ताम्र
+इल्म
+फैलता
+समतुल्य
+किरणें
+पेव्ड
+हुमायूँ
+सईद
+भाभी
+अंडमान
+चूक
+रणधीर
+इब्न
+बो
+बॉस
+उपराष्ट्रपति
+वू
+स्पीकर
+च्वाइस
+स्टुअर्ट
+प्रदाताओं
+कार्गो
+डेन्जोंगपा
+महज
+सीतापुर
+लगान
+पेंटल
+अनुसूची
+हस्तियों
+बहू
+कुलीन
+किनारा
+कुलकर्णी
+धनराशि
+छुटकारा
+बगीचे
+शिरा
+देखती
+हीन
+मद
+बीट
+वर्धित
+संभाला
+नीच
+बेंज
+जम
+जप
+गियर
+एफएम
+आरोपित
+सोन
+ठाकरे
+स्टीवर्ट
+पाण्डेय
+आयकर
+स्वार्थ
+जन्मतिथि
+विज्ञप्ति
+न्
+रीज़न
+म्हणौनि
+वत
+रणनीतिक
+शु
+अत्याधिक
+खालसा
+प्रान्तों
+कैलोरी
+१२०
+विनिर्देश
+अमावस्या
+गोलियों
+जिन्दगी
+अशुद्ध
+स्मिता
+वार्तालाप
+दाखिल
+काउबॉय
+एक्टर्स
+टेनेसी
+पराबैंगनी
+घूमती
+खुलने
+हिरण
+संचारित
+लैला
+लाभप्रद
+प्वाइंट
+नर्तक
+जासूसी
+मानवों
+शाहपुर
+गुड़िया
+अनुग्रह
+९५
+विश्लेषक
+जहांगीर
+ही।
+त्रिशूल
+मनीश
+स्पैरो
+कोंकणी
+सेक्टर
+रिवर
+यथासंभव
+साम्यवाद
+हडसन
+सेव
+चैंपियंस
+बसों
+किपलिंग
+लड़
+विकिपिडिया
+घनिष्ठ
+दीवारें
+टॉक
+क्रमपरिवर्तन
+म्यूजियम
+प्लान
+केसरी
+फैमिली
+लातिन
+आर्द्रता
+घाना
+अस्मिता
+बट
+छड़ी
+कात्यायन
+पुनर्जन्म
+ग्लूकोज़
+अज्ञेय
+फिटनेस
+प्रतिभाशाली
+कलाकृतियों
+हीलियम
+दोहा
+अंधेरे
+तापीय
+मल्टी
+टीकू
+आर्किटेक्चर
+किन्हीं
+सत्यापन
+बलूचिस्तान
+लारा
+फिशर
+रिहा
+देवा
+गॉड
+सुनाया
+वेश
+सबौर
+प्रशान्त
+चिंताओं
+तंजानिया
+जाएँ।
+संयोजी
+साँचों
+पूछ
+श्राद्ध
+मात
+टैंगो
+अमरनाथ
+जानकार
+कृषक
+पेले
+गुणसूत्र
+पहियों
+जिज्ञासा
+टिप्पणियों
+कहलाने
+मोनोक्रोम
+हीरालाल
+बारीक
+देंगे।
+चित
+छोड़ते
+क़ुरान
+यमन
+आदर्शों
+अपन
+संघटन
+विषयवस्तु
+आमदनी
+स्क्वैश
+दर्शनों
+सूरदास
+मातृभूमि
+फेंकने
+१९५३
+दोस्ताना
+लैण्ड
+योजन
+लॉर्ड्स
+अभि
+यूएफओ
+विध्वंस
+भूपति
+नदाल
+प्रतिभूतियों
+ट्री
+टॉमी
+संप्रदायों
+६२
+वैयक्तिक
+भेजता
+मल्टीमीडिया
+आयामी
+गुड़
+ट्रॉफी
+आविष्कारक
+हुईं।
+लॉयड
+चिह्नों
+बिशप
+साँप
+हेवी
+पर्यवेक्षण
+ाद
+चिन्ता
+आलम
+चौबीस
+तलसानिया
+ताड़
+दायित्वों
+गलतियाँ
+रिएक्टर
+चंद्रगुप्त
+सप्तम
+नाइजीरिया
+स्थ
+गुदा
+त्यों
+मिटटी
+कर्ज़
+बॉन
+६७
+तात्कालिक
+गार्डनर
+अनूठा
+ओड़िआ
+रीटा
+विश्लेषणात्मक
+देवरिया
+नेवर
+्दी
+चिकनी
+डेटिंग
+पोर्टेबल
+उगाया
+बालकों
+स्पोर्ट
+१९५१
+द्रोण
+आवंटित
+गांगुली
+नार्वे
+यन्त्र
+देशपांडे
+८२
+प्याज
+एसएमएस
+तूं
+संहार
+अलौली
+शकीरा
+छू
+देवकी
+गोल्डबर्ग
+मशीनें
+कर्ज
+चढ़ने
+हिमानी
+बतलाया
+बंगलुरु
+पढाई
+नेम
+फ़ैसला
+प्रीतम
+हिरासत
+मुबारक
+खा०प०
+डिप्लोमा
+कॉनकॉर्ड
+समझकर
+संदर्म
+एलर्जी
+नितांत
+उठने
+मेरिल
+गोपनीय
+सुगम
+क़ी
+ाखण्ड
+युग्म
+बढ़ना
+अबाउट
+वहा
+चला।
+वतन
+बाधाओं
+हुबली
+हीट
+फुल
+अनुपस्थित
+येल
+भावुक
+पित्ताशय
+टिन
+लड़ा
+रॉकी
+नोल्स
+वमन
+मारना
+ब्लाक
+बहोत
+कूपर
+करो।
+प्रमाणपत्र
+यूट्यूब
+सम्मलेन
+रनवे
+पूँजी
+मंडप
+पोटेशियम
+उत्तरांचल
+ठेठ
+ओडिशा
+पल्लव
+इन्दौर
+तर्ज़
+ः
+अनूप
+आओ
+कुख्यात
+बांसुरी
+अनुपयुक्त
+मगरमच्छ
+स्पा
+सेबी
+चाहा
+धमनियों
+बारें
+अश्व
+हस्तिनापुर
+ईसाइयों
+आइपॉड
+१०१
+इराकी
+रयान
+ाल
+हिमनद
+अमरावती
+गिरी
+पूछने
+प्रेषित
+घटाने
+डिस्कवरी
+पथरी
+रायबरेली
+नायनमार
+बढती
+मिलेगी
+किशोरों
+साड़ी
+शिवजी
+पुनर्वास
+सहरसा
+कैरोलिना
+आरण्यक
+असुर
+लौंग
+समाविष्ट
+ज़ोन
+फकीर
+बियोवुल्फ़
+राइस
+थेफ्ट
+लू
+ल०
+अज़ाब
+वेबदुनिया
+ल्यूकेमिया
+मार्गरेट
+संन्यास
+रनों
+सुनहरे
+सबने
+विरल
+पॉलिसी
+रश
+कैमरों
+एंजेल्स
+प्राणायाम
+सेलिब्रिटी
+कण्डारस्यूं
+शाश्वत
+जुलूस
+विश
+जेफ
+मतानुसार
+उत्पात
+मामा
+७३
+रहीं।
+क्लिंटन
+विकिया
+आइवी
+लिस्ट
+आबू
+गोमती
+पुरुषोत्तम
+उत्तराखण्
+हेराल्ड
+दांता
+पद्मश्री
+शर्तें
+कटिहार
+स्विंग
+उत्तरार्द्ध
+सिंगल्स
+केदार
+रघु
+वासना
+पहुँचकर
+न्यूकैसल
+मांगी
+अमल
+सल्फर
+छोड
+अंजना
+कंप्यूटरों
+ढ
+विलिस
+सीकर
+जुड़ता
+प्रसन्नता
+प्लेटफॉर्म
+गिरि
+उछाल
+करीना
+जहर
+मासके
+सम्पदा
+चौदहवीं
+ढाईज्यूली
+साओ
+कोचीन
+श्रावण
+अर्पित
+मासूम
+टीन
+स्पार्क
+कट्टर
+चढ़ा
+ट्रिब्यून
+होंडा
+कीये
+एंटोनियो
+लैस
+किससे
+एकजुट
+पतंग
+१९२७
+टीकाकरण
+मूक
+असरगंज
+सतहों
+नाल
+आयताकार
+चढ़ाव
+कार्यशील
+दक्षिणपूर्व
+माथे
+मर्फी
+गुजरता
+सफ़र
+स्लोवेनिया
+रिले
+कॉमन
+जमाव
+कुलभूषण
+्स
+क्रोम
+उजाला
+मूत्राशय
+इस्राइल
+नाड़ी
+ंवत
+परगना
+लैंडिंग
+रेलगाड़ी
+कलाँ
+उद्धार
+ज़रिये
+शॉर्ट
+टिक
+डिज़नी
+फिल्माया
+मरते
+निष्कर्षों
+उलट
+भीमसेन
+चक्रों
+मात्राओं
+प्रणाम
+सिम्बियन
+संस्थागत
+बिताने
+आंग्ल
+बिजनौर
+फायदे
+खेड़ा
+कार्यभार
diff --git a/src/ArabicPUASimplified.txt b/src/ArabicPUASimplified.txt
new file mode 100644
index 000000000..a74ef266f
--- /dev/null
+++ b/src/ArabicPUASimplified.txt
@@ -0,0 +1,250 @@
+#
+# Name: Legacy Simplified Arabic encoding
+#
+# Format: Three tab-separated columns
+# Column #1 is the PUA code (in hex as 0xXXXX)
+# Column #2 is the Unicode (in hex as 0xXXXX)
+# Column #3 is the Unicode name (follows a comment sign, '#')
+#
+# The entries are in PUA order
+#
+0xF100 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
+0xF100 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
+0xF100 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
+0xF100 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
+0xF100 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0xF100 0x0653 # ARABIC MADDAH ABOVE
+0xF100 0x0654 # ARABIC HAMZA ABOVE
+0xF100 0x0655 # ARABIC HAMZA BELOW
+0xF100 0x0656 # ARABIC SUBSCRIPT ALEF
+0xF100 0x0657 # ARABIC INVERTED DAMMA
+0xF100 0x0658 # ARABIC MARK NOON GHUNNA
+0xF100 0x0659 # ARABIC ZWARAKAY
+0xF100 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
+0xF100 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
+0xF100 0x065C # ARABIC VOWEL SIGN DOT BELOW
+0xF100 0x065D # ARABIC REVERSED DAMMA
+0xF100 0x065E # ARABIC FATHA WITH TWO DOTS
+0xF10C 0x200C # ZERO WIDTH NON-JOINER
+0xF10D 0x200D # ZERO WIDTH JOINER
+0xF10E 0x200E # LEFT-TO-RIGHT MARK
+0xF10F 0x200F # RIGHT-TO-LEFT MARK
+0xF120 0x0020 # SPACE
+0xF121 0x0021 # EXCLAMATION MARK
+0xF122 0x0022 # QUOTATION MARK
+0xF123 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xF124 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xF125 0x0025 # PERCENT SIGN
+0xF126 0x00D7 # MULTIPLICATION SIGN
+0xF127 0x00F7 # DIVISION SIGN
+0xF128 0x0028 # LEFT PARENTHESIS
+0xF129 0x0029 # RIGHT PARENTHESIS
+0xF12A 0x002A # ASTERISK
+0xF12B 0x002B # PLUS SIGN
+0xF12C 0x060C # ARABIC COMMA
+0xF12D 0x002D # HYPHEN-MINUS
+0xF12E 0x002E # FULL STOP
+0xF12F 0x002F # SOLIDUS
+0xF130 0x0660 # ARABIC-INDIC DIGIT ZERO
+0xF131 0x0661 # ARABIC-INDIC DIGIT ONE
+0xF132 0x0662 # ARABIC-INDIC DIGIT TWO
+0xF133 0x0663 # ARABIC-INDIC DIGIT THREE
+0xF134 0x0664 # ARABIC-INDIC DIGIT FOUR
+0xF135 0x0665 # ARABIC-INDIC DIGIT FIVE
+0xF136 0x0666 # ARABIC-INDIC DIGIT SIX
+0xF137 0x0667 # ARABIC-INDIC DIGIT SEVEN
+0xF138 0x0668 # ARABIC-INDIC DIGIT EIGHT
+0xF139 0x0669 # ARABIC-INDIC DIGIT NINE
+0xF13A 0x003A # COLON
+0xF13B 0x003B # SEMICOLON
+0xF13B 0x061B # ARABIC SEMICOLON
+0xF13C 0x2018 # LEFT SINGLE QUOTATION MARK
+0xF13D 0x003D # EQUALS SIGN
+0xF13E 0x2019 # RIGHT SINGLE QUOTATION MARK
+0xF13F 0x003F # QUESTION MARK
+0xF13F 0x061F # ARABIC QUESTION MARK
+0xF141 0x0627 # ARABIC LETTER ALEF
+0xF141 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
+0xF142 0xFE8E # ARABIC LETTER ALEF FINAL FORM
+0xF143 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
+0xF143 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
+0xF144 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
+0xF145 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
+0xF145 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
+0xF146 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
+0xF147 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
+0xF147 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
+0xF148 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
+0xF149 0xFE91 # ARABIC LETTER BEH INITIAL FORM
+0xF149 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
+0xF14A 0x0628 # ARABIC LETTER BEH
+0xF14A 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
+0xF14A 0xFE90 # ARABIC LETTER BEH FINAL FORM
+0xF14B 0xFE97 # ARABIC LETTER TEH INITIAL FORM
+0xF14B 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
+0xF14C 0x062A # ARABIC LETTER TEH
+0xF14C 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
+0xF14C 0xFE96 # ARABIC LETTER TEH FINAL FORM
+0xF14D 0xFE9B # ARABIC LETTER THEH INITIAL FORM
+0xF14D 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
+0xF14E 0x062B # ARABIC LETTER THEH
+0xF14E 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
+0xF14E 0xFE9A # ARABIC LETTER THEH FINAL FORM
+0xF14F 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
+0xF14F 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
+0xF150 0xFE9E # ARABIC LETTER JEEM FINAL FORM
+0xF151 0x062C # ARABIC LETTER JEEM
+0xF151 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
+0xF152 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
+0xF152 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
+0xF153 0xFEA2 # ARABIC LETTER HAH FINAL FORM
+0xF154 0x062D # ARABIC LETTER HAH
+0xF154 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
+0xF155 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
+0xF155 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
+0xF156 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
+0xF157 0x062E # ARABIC LETTER KHAH
+0xF157 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
+0xF158 0x062F # ARABIC LETTER DAL
+0xF158 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
+0xF158 0xFEAA # ARABIC LETTER DAL FINAL FORM
+0xF159 0x0630 # ARABIC LETTER THAL
+0xF159 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
+0xF159 0xFEAC # ARABIC LETTER THAL FINAL FORM
+0xF15A 0x0631 # ARABIC LETTER REH
+0xF15A 0xFEAD # ARABIC LETTER REH ISOLATED FORM
+0xF15A 0xFEAE # ARABIC LETTER REH FINAL FORM
+0xF15B 0x005B # LEFT SQUARE BRACKET
+0xF15C 0x005C # REVERSE SOLIDUS
+0xF15D 0x005D # RIGHT SQUARE BRACKET
+0xF15E 0x002C # COMMA
+0xF15E 0x066B # ARABIC DECIMAL SEPARATOR
+0xF15E 0x066C # ARABIC THOUSANDS SEPARATOR
+0xF15F 0x0640 # ARABIC TATWEEL
+0xF160 0x0632 # ARABIC LETTER ZAIN
+0xF160 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
+0xF160 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
+0xF161 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
+0xF161 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
+0xF162 0x0633 # ARABIC LETTER SEEN
+0xF162 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
+0xF162 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
+0xF163 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
+0xF163 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
+0xF164 0x0634 # ARABIC LETTER SHEEN
+0xF164 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
+0xF164 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
+0xF165 0xFEBB # ARABIC LETTER SAD INITIAL FORM
+0xF165 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
+0xF166 0x0635 # ARABIC LETTER SAD
+0xF166 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
+0xF166 0xFEBA # ARABIC LETTER SAD FINAL FORM
+0xF167 0xFEBF # ARABIC LETTER DAD INITIAL FORM
+0xF167 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
+0xF168 0x0636 # ARABIC LETTER DAD
+0xF168 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
+0xF168 0xFEBE # ARABIC LETTER DAD FINAL FORM
+0xF169 0x0637 # ARABIC LETTER TAH
+0xF169 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
+0xF169 0xFEC2 # ARABIC LETTER TAH FINAL FORM
+0xF169 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
+0xF169 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM
+0xF16A 0x0638 # ARABIC LETTER ZAH
+0xF16A 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
+0xF16A 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
+0xF16A 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
+0xF16A 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
+0xF16B 0xFECB # ARABIC LETTER AIN INITIAL FORM
+0xF16C 0xFECC # ARABIC LETTER AIN MEDIAL FORM
+0xF16D 0xFECA # ARABIC LETTER AIN FINAL FORM
+0xF16E 0x0639 # ARABIC LETTER AIN
+0xF16E 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
+0xF16F 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
+0xF170 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
+0xF171 0xFECE # ARABIC LETTER GHAIN FINAL FORM
+0xF172 0x063A # ARABIC LETTER GHAIN
+0xF172 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
+0xF173 0xFED3 # ARABIC LETTER FEH INITIAL FORM
+0xF174 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
+0xF175 0x0641 # ARABIC LETTER FEH
+0xF175 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
+0xF175 0xFED2 # ARABIC LETTER FEH FINAL FORM
+0xF176 0xFED7 # ARABIC LETTER QAF INITIAL FORM
+0xF177 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
+0xF178 0x0642 # ARABIC LETTER QAF
+0xF178 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
+0xF178 0xFED6 # ARABIC LETTER QAF FINAL FORM
+0xF179 0xFEDB # ARABIC LETTER KAF INITIAL FORM
+0xF179 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
+0xF17A 0x0643 # ARABIC LETTER KAF
+0xF17A 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
+0xF17A 0xFEDA # ARABIC LETTER KAF FINAL FORM
+0xF17B 0xFEDF # ARABIC LETTER LAM INITIAL FORM
+0xF17B 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
+0xF17C 0x0644 # ARABIC LETTER LAM
+0xF17C 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
+0xF17C 0xFEDE # ARABIC LETTER LAM FINAL FORM
+0xF17D 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
+0xF17D 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
+0xF17E 0x0645 # ARABIC LETTER MEEM
+0xF17E 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
+0xF17E 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
+0xF17F 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
+0xF17F 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
+0xF1A1 0xFEEB # ARABIC LETTER HEH INITIAL FORM
+0xF1A2 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
+0xF1A3 0xFEEA # ARABIC LETTER HEH FINAL FORM
+0xF1A4 0x0647 # ARABIC LETTER HEH
+0xF1A4 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
+0xF1A5 0x0648 # ARABIC LETTER WAW
+0xF1A5 0xFEED # ARABIC LETTER WAW ISOLATED FORM
+0xF1A5 0xFEEE # ARABIC LETTER WAW FINAL FORM
+0xF1A6 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
+0xF1A6 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
+0xF1A7 0xFEF2 # ARABIC LETTER YEH FINAL FORM
+0xF1A8 0x064A # ARABIC LETTER YEH
+0xF1A8 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
+0xF1A9 0x0629 # ARABIC LETTER TEH MARBUTA
+0xF1A9 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
+0xF1AA 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
+0xF1AB 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
+0xF1AC 0x0649 # ARABIC LETTER ALEF MAKSURA
+0xF1AC 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
+0xF1AD 0x0621 # ARABIC LETTER HAMZA
+0xF1AE 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
+0xF1AE 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
+0xF1AF 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
+0xF1B0 0x0030 # DIGIT ZERO
+0xF1B1 0x0031 # DIGIT ONE
+0xF1B2 0x0032 # DIGIT TWO
+0xF1B3 0x0033 # DIGIT THREE
+0xF1B4 0x0034 # DIGIT FOUR
+0xF1B5 0x0035 # DIGIT FIVE
+0xF1B6 0x0036 # DIGIT SIX
+0xF1B7 0x0037 # DIGIT SEVEN
+0xF1B8 0x0038 # DIGIT EIGHT
+0xF1B9 0x0039 # DIGIT NINE
+0xF1BA 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
+0xF1BA 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
+0xF1BB 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
+0xF1BB 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
+0xF1BB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
+0xF1BC 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+0xF1BD 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
+0xF1BE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
+0xF1BF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
+0xF1C0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
+0xF1C1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
+0xF1C2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
+0xF1C3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
+0xF1C4 0x064E # ARABIC FATHA
+0xF1C5 0x064F # ARABIC DAMMA
+0xF1C6 0x0652 # ARABIC SUKUN
+0xF1C7 0x064B # ARABIC FATHATAN
+0xF1C8 0x064C # ARABIC DAMMATAN
+0xF1C9 0x0651 # ARABIC SHADDA
+0xF1CA 0x0650 # ARABIC KASRA
+0xF1CB 0x064D # ARABIC KASRATAN
+0xF1E1 0x0646 # ARABIC LETTER NOON
+0xF1E1 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
+0xF1E1 0xFEE6 # ARABIC LETTER NOON FINAL FORM
diff --git a/src/ArabicPUATraditional.txt b/src/ArabicPUATraditional.txt
new file mode 100644
index 000000000..e14b383c9
--- /dev/null
+++ b/src/ArabicPUATraditional.txt
@@ -0,0 +1,295 @@
+#
+# Name: Legacy Traditional Arabic encoding
+#
+# Format: Three tab-separated columns
+# Column #1 is the PUA code (in hex as 0xXXXX)
+# Column #2 is the Unicode (in hex as 0xXXXX)
+# Column #3 is the Unicode name (follows a comment sign, '#')
+#
+# The entries are in PUA order
+#
+0xF200 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
+0xF200 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
+0xF200 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
+0xF200 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
+0xF200 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0xF200 0x0653 # ARABIC MADDAH ABOVE
+0xF200 0x0654 # ARABIC HAMZA ABOVE
+0xF200 0x0655 # ARABIC HAMZA BELOW
+0xF200 0x0656 # ARABIC SUBSCRIPT ALEF
+0xF200 0x0657 # ARABIC INVERTED DAMMA
+0xF200 0x0658 # ARABIC MARK NOON GHUNNA
+0xF200 0x0659 # ARABIC ZWARAKAY
+0xF200 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
+0xF200 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
+0xF200 0x065C # ARABIC VOWEL SIGN DOT BELOW
+0xF200 0x065D # ARABIC REVERSED DAMMA
+0xF200 0x065E # ARABIC FATHA WITH TWO DOTS
+0xF202 0xFC08 # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM
+0xF203 0xFC0E # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM
+0xF204 0xFC12 # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM
+0xF205 0xFC42 # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM
+0xF206 0xFC4E # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM
+0xF20C 0x200C # ZERO WIDTH NON-JOINER
+0xF20D 0x200D # ZERO WIDTH JOINER
+0xF20E 0x200E # LEFT-TO-RIGHT MARK
+0xF20F 0x200F # RIGHT-TO-LEFT MARK
+0xF210 0xFD88 # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM
+0xF212 0xFC3F # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM
+0xF213 0xFC40 # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM
+0xF214 0xFC41 # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM
+0xF215 0xFC6A # ARABIC LIGATURE BEH WITH REH FINAL FORM
+0xF216 0xFC70 # ARABIC LIGATURE TEH WITH REH FINAL FORM
+0xF217 0xFC91 # ARABIC LIGATURE YEH WITH REH FINAL FORM
+0xF218 0xFCB0 # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM
+0xF219 0xFD30 # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM
+0xF21A 0xFCCD # ARABIC LIGATURE LAM WITH HEH INITIAL FORM
+0xF21C 0xFC44 # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM
+0xF21D 0xFC0A # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM
+0xF21E 0xFC10 # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM
+0xF21F 0xFC50 # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM
+0xF220 0x0020 # SPACE
+0xF221 0x0021 # EXCLAMATION MARK
+0xF222 0x0022 # QUOTATION MARK
+0xF223 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xF224 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xF225 0x0025 # PERCENT SIGN
+0xF226 0x00D7 # MULTIPLICATION SIGN
+0xF227 0x00F7 # DIVISION SIGN
+0xF228 0x0028 # LEFT PARENTHESIS
+0xF229 0x0029 # RIGHT PARENTHESIS
+0xF22A 0x002A # ASTERISK
+0xF22B 0x002B # PLUS SIGN
+0xF22C 0x060C # ARABIC COMMA
+0xF22D 0x002D # HYPHEN-MINUS
+0xF22E 0x002E # FULL STOP
+0xF22F 0x002F # SOLIDUS
+0xF230 0x0660 # ARABIC-INDIC DIGIT ZERO
+0xF231 0x0661 # ARABIC-INDIC DIGIT ONE
+0xF232 0x0662 # ARABIC-INDIC DIGIT TWO
+0xF233 0x0663 # ARABIC-INDIC DIGIT THREE
+0xF234 0x0664 # ARABIC-INDIC DIGIT FOUR
+0xF235 0x0665 # ARABIC-INDIC DIGIT FIVE
+0xF236 0x0666 # ARABIC-INDIC DIGIT SIX
+0xF237 0x0667 # ARABIC-INDIC DIGIT SEVEN
+0xF238 0x0668 # ARABIC-INDIC DIGIT EIGHT
+0xF239 0x0669 # ARABIC-INDIC DIGIT NINE
+0xF23A 0x003A # COLON
+0xF23B 0x003B # SEMICOLON
+0xF23B 0x061B # ARABIC SEMICOLON
+0xF23C 0x201C # LEFT DOUBLE QUOTATION MARK
+0xF23D 0x003D # EQUALS SIGN
+0xF23E 0x201D # RIGHT DOUBLE QUOTATION MARK
+0xF23F 0x003F # QUESTION MARK
+0xF23F 0x061F # ARABIC QUESTION MARK
+0xF241 0x0627 # ARABIC LETTER ALEF
+0xF241 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
+0xF242 0xFE8E # ARABIC LETTER ALEF FINAL FORM
+0xF243 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
+0xF243 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
+0xF244 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
+0xF245 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
+0xF245 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
+0xF246 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
+0xF247 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
+0xF247 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
+0xF248 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
+0xF249 0xFE91 # ARABIC LETTER BEH INITIAL FORM
+0xF24A 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
+0xF24B 0xFE90 # ARABIC LETTER BEH FINAL FORM
+0xF24C 0x0628 # ARABIC LETTER BEH
+0xF24C 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
+0xF24D 0xFE97 # ARABIC LETTER TEH INITIAL FORM
+0xF24E 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
+0xF24F 0xFE96 # ARABIC LETTER TEH FINAL FORM
+0xF250 0x062A # ARABIC LETTER TEH
+0xF250 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
+0xF251 0xFE9B # ARABIC LETTER THEH INITIAL FORM
+0xF252 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
+0xF253 0xFE9A # ARABIC LETTER THEH FINAL FORM
+0xF254 0x062B # ARABIC LETTER THEH
+0xF254 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
+0xF255 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
+0xF256 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
+0xF257 0xFE9E # ARABIC LETTER JEEM FINAL FORM
+0xF258 0x062C # ARABIC LETTER JEEM
+0xF258 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
+0xF259 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
+0xF25A 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
+0xF25B 0x005B # LEFT SQUARE BRACKET
+0xF25C 0xFEA2 # ARABIC LETTER HAH FINAL FORM
+0xF25D 0x005D # RIGHT SQUARE BRACKET
+0xF25E 0x002C # COMMA
+0xF25E 0x066B # ARABIC DECIMAL SEPARATOR
+0xF25E 0x066C # ARABIC THOUSANDS SEPARATOR
+0xF25F 0x0640 # ARABIC TATWEEL
+0xF260 0x062D # ARABIC LETTER HAH
+0xF260 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
+0xF261 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
+0xF262 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
+0xF263 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
+0xF264 0x062E # ARABIC LETTER KHAH
+0xF264 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
+0xF265 0x062F # ARABIC LETTER DAL
+0xF265 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
+0xF266 0xFEAA # ARABIC LETTER DAL FINAL FORM
+0xF267 0x0630 # ARABIC LETTER THAL
+0xF267 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
+0xF268 0xFEAC # ARABIC LETTER THAL FINAL FORM
+0xF269 0x0631 # ARABIC LETTER REH
+0xF269 0xFEAD # ARABIC LETTER REH ISOLATED FORM
+0xF26A 0xFEAE # ARABIC LETTER REH FINAL FORM
+0xF26B 0x0632 # ARABIC LETTER ZAIN
+0xF26B 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
+0xF26C 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
+0xF26D 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
+0xF26E 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
+0xF26F 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
+0xF270 0x0633 # ARABIC LETTER SEEN
+0xF270 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
+0xF271 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
+0xF272 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
+0xF273 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
+0xF274 0x0634 # ARABIC LETTER SHEEN
+0xF274 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
+0xF275 0xFEBB # ARABIC LETTER SAD INITIAL FORM
+0xF276 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
+0xF277 0xFEBA # ARABIC LETTER SAD FINAL FORM
+0xF278 0x0635 # ARABIC LETTER SAD
+0xF278 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
+0xF279 0xFEBF # ARABIC LETTER DAD INITIAL FORM
+0xF27A 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
+0xF27B 0xFD3E # ORNATE LEFT PARENTHESIS
+0xF27C 0xFEBE # ARABIC LETTER DAD FINAL FORM
+0xF27D 0xFD3F # ORNATE RIGHT PARENTHESIS
+0xF27E 0x0636 # ARABIC LETTER DAD
+0xF27E 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
+0xF27F 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
+0xF280 0xFC9C # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM
+0xF281 0xFC9D # ARABIC LIGATURE BEH WITH HAH INITIAL FORM
+0xF282 0xFC9E # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM
+0xF283 0xFCA1 # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM
+0xF284 0xFCA2 # ARABIC LIGATURE TEH WITH HAH INITIAL FORM
+0xF285 0xFCA3 # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM
+0xF286 0xFCC9 # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM
+0xF287 0xFCCA # ARABIC LIGATURE LAM WITH HAH INITIAL FORM
+0xF288 0xFCCB # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM
+0xF289 0xFCCE # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM
+0xF28A 0xFCCF # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM
+0xF28B 0xFCD0 # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM
+0xF28D 0xFCD2 # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM
+0xF28E 0xFCD3 # ARABIC LIGATURE NOON WITH HAH INITIAL FORM
+0xF28F 0xFCDA # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM
+0xF290 0xFCDB # ARABIC LIGATURE YEH WITH HAH INITIAL FORM
+0xF291 0xFCDC # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM
+0xF292 0xFC6D # ARABIC LIGATURE BEH WITH NOON FINAL FORM
+0xF293 0xFC73 # ARABIC LIGATURE TEH WITH NOON FINAL FORM
+0xF294 0xFC94 # ARABIC LIGATURE YEH WITH NOON FINAL FORM
+0xF295 0xFC86 # ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM
+0xF296 0xFC9F # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM
+0xF297 0xFCA4 # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM
+0xF298 0xFCD5 # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM
+0xF299 0xFCDD # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM
+0xF29A 0xFCA8 # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM
+0xF29B 0xFCAA # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM
+0xF29C 0xFCAC # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM
+0xF29D 0xFCCC # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM
+0xF29E 0xFCD1 # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM
+0xF29F 0xFC32 # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM
+0xF2A1 0xFEC2 # ARABIC LETTER TAH FINAL FORM
+0xF2A2 0x0637 # ARABIC LETTER TAH
+0xF2A2 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
+0xF2A3 0x0638 # ARABIC LETTER ZAH
+0xF2A3 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
+0xF2A4 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
+0xF2A5 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
+0xF2A6 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
+0xF2A7 0xFECB # ARABIC LETTER AIN INITIAL FORM
+0xF2A8 0xFECC # ARABIC LETTER AIN MEDIAL FORM
+0xF2A9 0xFECA # ARABIC LETTER AIN FINAL FORM
+0xF2AA 0x0639 # ARABIC LETTER AIN
+0xF2AA 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
+0xF2AB 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
+0xF2AC 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
+0xF2AD 0xFECE # ARABIC LETTER GHAIN FINAL FORM
+0xF2AE 0x063A # ARABIC LETTER GHAIN
+0xF2AE 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
+0xF2AF 0xFED3 # ARABIC LETTER FEH INITIAL FORM
+0xF2B0 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
+0xF2B1 0xFED2 # ARABIC LETTER FEH FINAL FORM
+0xF2B2 0x0641 # ARABIC LETTER FEH
+0xF2B2 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
+0xF2B3 0xFED7 # ARABIC LETTER QAF INITIAL FORM
+0xF2B4 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
+0xF2B5 0xFED6 # ARABIC LETTER QAF FINAL FORM
+0xF2B6 0x0642 # ARABIC LETTER QAF
+0xF2B6 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
+0xF2B7 0xFEDB # ARABIC LETTER KAF INITIAL FORM
+0xF2B8 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
+0xF2B9 0xFEDA # ARABIC LETTER KAF FINAL FORM
+0xF2BA 0x0643 # ARABIC LETTER KAF
+0xF2BA 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
+0xF2BB 0xFEDF # ARABIC LETTER LAM INITIAL FORM
+0xF2BC 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
+0xF2BD 0xFEDE # ARABIC LETTER LAM FINAL FORM
+0xF2BE 0x0644 # ARABIC LETTER LAM
+0xF2BE 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
+0xF2BF 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
+0xF2C0 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
+0xF2C1 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
+0xF2C2 0x0645 # ARABIC LETTER MEEM
+0xF2C2 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
+0xF2C3 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
+0xF2C4 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
+0xF2C5 0xFEE6 # ARABIC LETTER NOON FINAL FORM
+0xF2C6 0x0646 # ARABIC LETTER NOON
+0xF2C6 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
+0xF2C7 0xFEEB # ARABIC LETTER HEH INITIAL FORM
+0xF2C8 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
+0xF2C9 0xFEEA # ARABIC LETTER HEH FINAL FORM
+0xF2CA 0x0647 # ARABIC LETTER HEH
+0xF2CA 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
+0xF2CB 0x0648 # ARABIC LETTER WAW
+0xF2CB 0xFEED # ARABIC LETTER WAW ISOLATED FORM
+0xF2CC 0xFEEE # ARABIC LETTER WAW FINAL FORM
+0xF2CD 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
+0xF2CE 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
+0xF2CF 0xFEF2 # ARABIC LETTER YEH FINAL FORM
+0xF2D0 0x064A # ARABIC LETTER YEH
+0xF2D0 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
+0xF2D1 0x0629 # ARABIC LETTER TEH MARBUTA
+0xF2D1 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
+0xF2D2 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
+0xF2D3 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
+0xF2D4 0x0649 # ARABIC LETTER ALEF MAKSURA
+0xF2D4 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
+0xF2D5 0x0621 # ARABIC LETTER HAMZA
+0xF2D6 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
+0xF2D7 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
+0xF2D8 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
+0xF2D9 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
+0xF2D9 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
+0xF2DA 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
+0xF2DA 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
+0xF2DB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
+0xF2DC 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
+0xF2DD 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+0xF2DE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
+0xF2DF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
+0xF2E0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
+0xF2E1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
+0xF2E2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
+0xF2E3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
+0xF2E4 0x064E # ARABIC FATHA
+0xF2E5 0x064F # ARABIC DAMMA
+0xF2E6 0x0652 # ARABIC SUKUN
+0xF2E7 0x064B # ARABIC FATHATAN
+0xF2E8 0x064C # ARABIC DAMMATAN
+0xF2E9 0x0651 # ARABIC SHADDA
+0xF2EA 0x0650 # ARABIC KASRA
+0xF2EB 0x064D # ARABIC KASRATAN
+0xF2EC 0xFC60 # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM
+0xF2ED 0xFC61 # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM
+0xF2EF 0xFC5E # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM
+0xF2F0 0xFC62 # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM
+0xF2F1 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM
diff --git a/src/Makefile.am b/src/Makefile.am
index c0c77055e..31399a6aa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,7 +12,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
-EXTRA_DIST += harfbuzz.cc
+EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
EXTRA_DIST += meson.build
EXTRA_DIST += fix_get_types.py
@@ -47,6 +47,9 @@ HBLIBS += $(GLIB_LIBS)
HBDEPS += $(GLIB_DEPS)
HBSOURCES += $(HB_GLIB_sources)
HBHEADERS += $(HB_GLIB_headers)
+HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1
+else
+HB_HAS_GLIB_DEF = undef HB_HAS_GLIB
endif
if HAVE_FREETYPE
@@ -55,6 +58,9 @@ HBLIBS += $(FREETYPE_LIBS)
HBDEPS += $(FREETYPE_DEPS)
HBSOURCES += $(HB_FT_sources)
HBHEADERS += $(HB_FT_headers)
+HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1
+else
+HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE
endif
if HAVE_GRAPHITE2
@@ -63,6 +69,9 @@ HBLIBS += $(GRAPHITE2_LIBS)
HBDEPS += $(GRAPHITE2_DEPS)
HBSOURCES += $(HB_GRAPHITE2_sources)
HBHEADERS += $(HB_GRAPHITE2_headers)
+HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1
+else
+HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE
endif
if HAVE_UNISCRIBE
@@ -70,6 +79,9 @@ HBCFLAGS += $(UNISCRIBE_CFLAGS)
HBNONPCLIBS += $(UNISCRIBE_LIBS)
HBSOURCES += $(HB_UNISCRIBE_sources)
HBHEADERS += $(HB_UNISCRIBE_headers)
+HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1
+else
+HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE
endif
if HAVE_DIRECTWRITE
@@ -77,6 +89,9 @@ HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
HBNONPCLIBS += $(DIRECTWRITE_LIBS)
HBSOURCES += $(HB_DIRECTWRITE_sources)
HBHEADERS += $(HB_DIRECTWRITE_headers)
+HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1
+else
+HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE
endif
if HAVE_GDI
@@ -84,6 +99,9 @@ HBCFLAGS += $(GDI_CXXFLAGS)
HBNONPCLIBS += $(GDI_LIBS)
HBSOURCES += $(HB_GDI_sources)
HBHEADERS += $(HB_GDI_headers)
+HB_HAS_GDI_DEF = define HB_HAS_GDI 1
+else
+HB_HAS_GDI_DEF = undef HB_HAS_GDI
endif
if HAVE_CORETEXT
@@ -91,6 +109,9 @@ HBCFLAGS += $(CORETEXT_CFLAGS)
HBNONPCLIBS += $(CORETEXT_LIBS)
HBSOURCES += $(HB_CORETEXT_sources)
HBHEADERS += $(HB_CORETEXT_headers)
+HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1
+else
+HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
endif
@@ -147,7 +168,7 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
cmakedir = $(libdir)/cmake/harfbuzz
cmake_DATA = harfbuzz-config.cmake
-EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
+EXTRA_DIST += hb-version.h.in hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
lib_LTLIBRARIES += libharfbuzz-subset.la
libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
@@ -160,12 +181,25 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in
+harfbuzz-subset.cc: Makefile.sources
+ $(AM_V_GEN) \
+ LANG=C; \
+ for f in \
+ $(HB_BASE_sources) \
+ $(HB_SUBSET_sources) \
+ ; do echo '#include "'$$f'"'; done | \
+ sort -u | \
+ grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
+ || ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
+BUILT_SOURCES += harfbuzz-subset.cc
+
if HAVE_ICU
if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS)
HBLIBS += $(ICU_LIBS)
HBSOURCES += $(HB_ICU_sources)
HBHEADERS += $(HB_ICU_headers)
+HB_HAS_ICU_DEF = define HB_HAS_ICU 1
else
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
@@ -175,6 +209,7 @@ libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
pkginclude_HEADERS += $(HB_ICU_headers)
pkgconfig_DATA += harfbuzz-icu.pc
+HB_HAS_ICU_DEF = undef HB_HAS_ICU
endif
endif
EXTRA_DIST += harfbuzz-icu.pc.in
@@ -214,6 +249,25 @@ EXTRA_DIST += \
$(NULL)
+BUILT_SOURCES += \
+ hb-features.h
+DISTCLEANFILES += \
+ hb-features.h
+
+hb-features.h: hb-features.h.in $(top_builddir)/config.status
+ $(AM_V_GEN) $(SED) \
+ -e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
+ -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+ -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+ -e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
+ -e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
+ -e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
+ -e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
+ -e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
+ -e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
+ "$<" > "$@" || ($(RM) "$@"; false)
+
+
%.pc: %.pc.in $(top_builddir)/config.status
$(AM_V_GEN) \
$(SED) -e 's@%prefix%@$(prefix)@g' \
@@ -284,6 +338,7 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
harfbuzz.cc: Makefile.sources
$(AM_V_GEN) \
+ LANG=C; \
for f in \
$(HB_BASE_sources) \
$(HB_GLIB_sources) \
@@ -294,6 +349,7 @@ harfbuzz.cc: Makefile.sources
$(HB_DIRECTWRITE_sources) \
$(HB_CORETEXT_sources) \
; do echo '#include "'$$f'"'; done | \
+ sort -u | \
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
BUILT_SOURCES += harfbuzz.cc
@@ -307,6 +363,7 @@ noinst_PROGRAMS = \
test-ot-glyphname \
test-gpos-size-params \
test-gsub-would-substitute \
+ test-use-table \
$(NULL)
bin_PROGRAMS =
@@ -334,6 +391,10 @@ test_ot_glyphname_SOURCES = test-ot-glyphname.cc
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
+test_use_table_SOURCES = test-use-table.cc
+test_use_table_CPPFLAGS = $(HBCFLAGS)
+test_use_table_LDADD = libharfbuzz.la $(HBLIBS)
+
test_gpos_size_params_SOURCES = test-gpos-size-params.cc
test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
@@ -345,16 +406,20 @@ test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
COMPILED_TESTS = \
test-algs \
test-array \
+ test-bimap \
test-iter \
+ test-machinery \
test-map \
+ test-multimap \
test-number \
test-ot-tag \
test-priority-queue \
test-set \
+ test-serialize \
test-unicode-ranges \
test-vector \
- test-bimap \
test-repacker \
+ test-classdef-graph \
$(NULL)
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
@@ -369,22 +434,26 @@ test_array_SOURCES = test-array.cc
test_array_CPPFLAGS = $(HBCFLAGS)
test_array_LDADD = libharfbuzz.la $(HBLIBS)
-test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
-test_priority_queue_CPPFLAGS = $(HBCFLAGS)
-test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
-
-test_repacker_SOURCES = test-repacker.cc hb-static.cc
-test_repacker_CPPFLAGS = $(HBCFLAGS)
-test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+test_bimap_SOURCES = test-bimap.cc hb-static.cc
+test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
test_iter_SOURCES = test-iter.cc hb-static.cc
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
+test_machinery_SOURCES = test-machinery.cc hb-static.cc
+test_machinery_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_machinery_LDADD = $(COMPILED_TESTS_LDADD)
+
test_map_SOURCES = test-map.cc hb-static.cc
test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_map_LDADD = $(COMPILED_TESTS_LDADD)
+test_multimap_SOURCES = test-multimap.cc hb-static.cc
+test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_multimap_LDADD = $(COMPILED_TESTS_LDADD)
+
test_number_SOURCES = test-number.cc hb-number.cc
test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_number_LDADD = $(COMPILED_TESTS_LDADD)
@@ -393,10 +462,26 @@ test_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
+test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
+test_priority_queue_CPPFLAGS = $(HBCFLAGS)
+test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
+
+test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-context.cc
+test_repacker_CPPFLAGS = $(HBCFLAGS)
+test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+
+test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc
+test_classdef_graph_CPPFLAGS = $(HBCFLAGS)
+test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+
test_set_SOURCES = test-set.cc hb-static.cc
test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_set_LDADD = $(COMPILED_TESTS_LDADD)
+test_serialize_SOURCES = test-serialize.cc hb-static.cc
+test_serialize_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_serialize_LDADD = $(COMPILED_TESTS_LDADD)
+
test_unicode_ranges_SOURCES = test-unicode-ranges.cc
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
@@ -405,10 +490,6 @@ test_vector_SOURCES = test-vector.cc hb-static.cc
test_vector_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_vector_LDADD = $(COMPILED_TESTS_LDADD)
-test_bimap_SOURCES = test-bimap.cc hb-static.cc
-test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
-test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
-
dist_check_SCRIPTS = \
check-c-linkage-decls.py \
check-externs.py \
@@ -427,6 +508,7 @@ endif
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
+ base_srcdir="$(srcdir)" \
builddir="$(builddir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
HBSOURCES="$(HBSOURCES)" \
@@ -455,7 +537,7 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
INTROSPECTION_SCANNER_ENV = CC="$(CC)"
HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
-HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
+HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 freetype2-2.0
HarfBuzz_0_0_gir_CFLAGS = \
$(INCLUDES) \
$(HBCFLAGS) \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 699dfdcaf..6c4fc5de7 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -25,6 +25,7 @@ HB_BASE_sources = \
hb-blob.cc \
hb-blob.hh \
hb-buffer-serialize.cc \
+ hb-buffer-verify.cc \
hb-buffer.cc \
hb-buffer.hh \
hb-cache.hh \
@@ -50,8 +51,8 @@ HB_BASE_sources = \
hb-map.cc \
hb-map.hh \
hb-meta.hh \
- hb-ms-feature-ranges.cc \
hb-ms-feature-ranges.hh \
+ hb-multimap.hh \
hb-mutex.hh \
hb-null.hh \
hb-number.cc \
@@ -88,6 +89,77 @@ HB_BASE_sources = \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-ot-layout-gsub-table.hh \
+ OT/glyf/glyf.hh \
+ OT/glyf/glyf-helpers.hh \
+ OT/glyf/loca.hh \
+ OT/glyf/path-builder.hh \
+ OT/glyf/Glyph.hh \
+ OT/glyf/GlyphHeader.hh \
+ OT/glyf/SimpleGlyph.hh \
+ OT/glyf/coord-setter.hh \
+ OT/glyf/composite-iter.hh \
+ OT/glyf/CompositeGlyph.hh \
+ OT/glyf/VarCompositeGlyph.hh \
+ OT/glyf/SubsetGlyph.hh \
+ OT/Layout/types.hh \
+ OT/Layout/Common/Coverage.hh \
+ OT/Layout/Common/CoverageFormat1.hh \
+ OT/Layout/Common/CoverageFormat2.hh \
+ OT/Layout/Common/RangeRecord.hh \
+ OT/Layout/GPOS/AnchorFormat1.hh \
+ OT/Layout/GPOS/AnchorFormat2.hh \
+ OT/Layout/GPOS/AnchorFormat3.hh \
+ OT/Layout/GPOS/Anchor.hh \
+ OT/Layout/GPOS/AnchorMatrix.hh \
+ OT/Layout/GPOS/ChainContextPos.hh \
+ OT/Layout/GPOS/Common.hh \
+ OT/Layout/GPOS/ContextPos.hh \
+ OT/Layout/GPOS/CursivePosFormat1.hh \
+ OT/Layout/GPOS/CursivePos.hh \
+ OT/Layout/GPOS/ExtensionPos.hh \
+ OT/Layout/GPOS/GPOS.hh \
+ OT/Layout/GPOS/LigatureArray.hh \
+ OT/Layout/GPOS/MarkArray.hh \
+ OT/Layout/GPOS/MarkBasePosFormat1.hh \
+ OT/Layout/GPOS/MarkBasePos.hh \
+ OT/Layout/GPOS/MarkLigPosFormat1.hh \
+ OT/Layout/GPOS/MarkLigPos.hh \
+ OT/Layout/GPOS/MarkMarkPosFormat1.hh \
+ OT/Layout/GPOS/MarkMarkPos.hh \
+ OT/Layout/GPOS/MarkRecord.hh \
+ OT/Layout/GPOS/PairPosFormat1.hh \
+ OT/Layout/GPOS/PairPosFormat2.hh \
+ OT/Layout/GPOS/PairPos.hh \
+ OT/Layout/GPOS/PairSet.hh \
+ OT/Layout/GPOS/PairValueRecord.hh \
+ OT/Layout/GPOS/PosLookup.hh \
+ OT/Layout/GPOS/PosLookupSubTable.hh \
+ OT/Layout/GPOS/SinglePosFormat1.hh \
+ OT/Layout/GPOS/SinglePosFormat2.hh \
+ OT/Layout/GPOS/SinglePos.hh \
+ OT/Layout/GPOS/ValueFormat.hh \
+ OT/Layout/GSUB/AlternateSet.hh \
+ OT/Layout/GSUB/AlternateSubstFormat1.hh \
+ OT/Layout/GSUB/AlternateSubst.hh \
+ OT/Layout/GSUB/ChainContextSubst.hh \
+ OT/Layout/GSUB/Common.hh \
+ OT/Layout/GSUB/ContextSubst.hh \
+ OT/Layout/GSUB/ExtensionSubst.hh \
+ OT/Layout/GSUB/GSUB.hh \
+ OT/Layout/GSUB/Ligature.hh \
+ OT/Layout/GSUB/LigatureSet.hh \
+ OT/Layout/GSUB/LigatureSubstFormat1.hh \
+ OT/Layout/GSUB/LigatureSubst.hh \
+ OT/Layout/GSUB/MultipleSubstFormat1.hh \
+ OT/Layout/GSUB/MultipleSubst.hh \
+ OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
+ OT/Layout/GSUB/ReverseChainSingleSubst.hh \
+ OT/Layout/GSUB/Sequence.hh \
+ OT/Layout/GSUB/SingleSubstFormat1.hh \
+ OT/Layout/GSUB/SingleSubstFormat2.hh \
+ OT/Layout/GSUB/SingleSubst.hh \
+ OT/Layout/GSUB/SubstLookup.hh \
+ OT/Layout/GSUB/SubstLookupSubTable.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.cc \
@@ -109,30 +181,29 @@ HB_BASE_sources = \
hb-ot-os2-unicode-ranges.hh \
hb-ot-post-macroman.hh \
hb-ot-post-table.hh \
- hb-ot-shape-complex-arabic-fallback.hh \
- hb-ot-shape-complex-arabic-joining-list.hh \
- hb-ot-shape-complex-arabic-table.hh \
- hb-ot-shape-complex-arabic-win1256.hh \
- hb-ot-shape-complex-arabic.cc \
- hb-ot-shape-complex-arabic.hh \
- hb-ot-shape-complex-default.cc \
- hb-ot-shape-complex-hangul.cc \
- hb-ot-shape-complex-hebrew.cc \
- hb-ot-shape-complex-indic-table.cc \
- hb-ot-shape-complex-indic.cc \
- hb-ot-shape-complex-indic.hh \
- hb-ot-shape-complex-khmer.cc \
- hb-ot-shape-complex-khmer.hh \
- hb-ot-shape-complex-myanmar.cc \
- hb-ot-shape-complex-myanmar.hh \
- hb-ot-shape-complex-syllabic.cc \
- hb-ot-shape-complex-syllabic.hh \
- hb-ot-shape-complex-thai.cc \
- hb-ot-shape-complex-use-table.hh \
- hb-ot-shape-complex-use.cc \
- hb-ot-shape-complex-vowel-constraints.cc \
- hb-ot-shape-complex-vowel-constraints.hh \
- hb-ot-shape-complex.hh \
+ hb-ot-shaper-arabic-fallback.hh \
+ hb-ot-shaper-arabic-joining-list.hh \
+ hb-ot-shaper-arabic-pua.hh \
+ hb-ot-shaper-arabic-table.hh \
+ hb-ot-shaper-arabic-win1256.hh \
+ hb-ot-shaper-arabic.cc \
+ hb-ot-shaper-arabic.hh \
+ hb-ot-shaper-default.cc \
+ hb-ot-shaper-hangul.cc \
+ hb-ot-shaper-hebrew.cc \
+ hb-ot-shaper-indic-table.cc \
+ hb-ot-shaper-indic.cc \
+ hb-ot-shaper-indic.hh \
+ hb-ot-shaper-khmer.cc \
+ hb-ot-shaper-myanmar.cc \
+ hb-ot-shaper-syllabic.cc \
+ hb-ot-shaper-syllabic.hh \
+ hb-ot-shaper-thai.cc \
+ hb-ot-shaper-use-table.hh \
+ hb-ot-shaper-use.cc \
+ hb-ot-shaper-vowel-constraints.cc \
+ hb-ot-shaper-vowel-constraints.hh \
+ hb-ot-shaper.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape-fallback.hh \
hb-ot-shape-normalize.cc \
@@ -181,19 +252,19 @@ HB_BASE_RAGEL_GENERATED_sources = \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text.hh \
hb-number-parser.hh \
- hb-ot-shape-complex-indic-machine.hh \
- hb-ot-shape-complex-khmer-machine.hh \
- hb-ot-shape-complex-myanmar-machine.hh \
- hb-ot-shape-complex-use-machine.hh \
+ hb-ot-shaper-indic-machine.hh \
+ hb-ot-shaper-khmer-machine.hh \
+ hb-ot-shaper-myanmar-machine.hh \
+ hb-ot-shaper-use-machine.hh \
$(NULL)
HB_BASE_RAGEL_sources = \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
hb-number-parser.rl \
- hb-ot-shape-complex-indic-machine.rl \
- hb-ot-shape-complex-khmer-machine.rl \
- hb-ot-shape-complex-myanmar-machine.rl \
- hb-ot-shape-complex-use-machine.rl \
+ hb-ot-shaper-indic-machine.rl \
+ hb-ot-shaper-khmer-machine.rl \
+ hb-ot-shaper-myanmar-machine.rl \
+ hb-ot-shaper-use-machine.rl \
$(NULL)
HB_BASE_headers = \
@@ -202,6 +273,7 @@ HB_BASE_headers = \
hb-blob.h \
hb-buffer.h \
hb-common.h \
+ hb-cplusplus.hh \
hb-deprecated.h \
hb-draw.h \
hb-face.h \
@@ -273,15 +345,28 @@ HB_SUBSET_sources = \
hb-subset-cff2.hh \
hb-subset-input.cc \
hb-subset-input.hh \
+ hb-subset-accelerator.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
+ hb-subset-repacker.cc \
hb-subset.cc \
hb-subset.hh \
hb-repacker.hh \
+ graph/graph.hh \
+ graph/gsubgpos-graph.hh \
+ graph/gsubgpos-context.hh \
+ graph/gsubgpos-context.cc \
+ graph/coverage-graph.hh \
+ graph/classdef-graph.hh \
+ graph/pairpos-graph.hh \
+ graph/markbasepos-graph.hh \
+ graph/split-helpers.hh \
+ graph/serialize.hh \
$(NULL)
HB_SUBSET_headers = \
hb-subset.h \
+ hb-subset-repacker.h \
$(NULL)
HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
diff --git a/src/OT/Layout/Common/Coverage.hh b/src/OT/Layout/Common/Coverage.hh
new file mode 100644
index 000000000..fbd7c642a
--- /dev/null
+++ b/src/OT/Layout/Common/Coverage.hh
@@ -0,0 +1,336 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGE_HH
+#define OT_LAYOUT_COMMON_COVERAGE_HH
+
+#include "../types.hh"
+#include "CoverageFormat1.hh"
+#include "CoverageFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template<typename Iterator>
+static inline void Coverage_serialize (hb_serialize_context_t *c,
+ Iterator it);
+
+struct Coverage
+{
+
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ CoverageFormat1_3<SmallTypes> format1;
+ CoverageFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+ CoverageFormat1_3<MediumTypes>format3;
+ CoverageFormat2_4<MediumTypes>format4;
+#endif
+ } 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));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.sanitize (c));
+ case 4: return_trace (u.format4.sanitize (c));
+#endif
+ default:return_trace (true);
+ }
+ }
+
+ /* Has interface. */
+ unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
+ /* Predicate. */
+ bool operator () (hb_codepoint_t k) const { return has (k); }
+
+ unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
+ unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_coverage (glyph_id);
+ case 2: return u.format2.get_coverage (glyph_id);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_coverage (glyph_id);
+ case 4: return u.format4.get_coverage (glyph_id);
+#endif
+ default:return NOT_COVERED;
+ }
+ }
+
+ unsigned get_population () const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_population ();
+ case 2: return u.format2.get_population ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_population ();
+ case 4: return u.format4.get_population ();
+#endif
+ default:return NOT_COVERED;
+ }
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
+ unsigned count = 0;
+ unsigned num_ranges = 0;
+ hb_codepoint_t last = (hb_codepoint_t) -2;
+ for (auto g: glyphs)
+ {
+ if (last + 1 != g)
+ num_ranges++;
+ last = g;
+ count++;
+ }
+ u.format = count <= num_ranges * 3 ? 1 : 2;
+
+#ifndef HB_NO_BEYOND_64K
+ if (count && last > 0xFFFFu)
+ u.format += 2;
+#endif
+
+ switch (u.format)
+ {
+ case 1: return_trace (u.format1.serialize (c, glyphs));
+ case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.serialize (c, glyphs));
+ case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
+ default:return_trace (false);
+ }
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto it =
+ + iter ()
+ | hb_filter (c->plan->glyph_map_gsub)
+ | hb_map_retains_sorting (c->plan->glyph_map_gsub)
+ ;
+
+ // 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 intersects (const hb_set_t *glyphs) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.intersects (glyphs);
+ case 2: return u.format2.intersects (glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersects (glyphs);
+ case 4: return u.format4.intersects (glyphs);
+#endif
+ default:return false;
+ }
+ }
+ bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.intersects_coverage (glyphs, index);
+ case 2: return u.format2.intersects_coverage (glyphs, index);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersects_coverage (glyphs, index);
+ case 4: return u.format4.intersects_coverage (glyphs, index);
+#endif
+ default:return false;
+ }
+ }
+
+ /* Might return false if array looks unsorted.
+ * Used for faster rejection of corrupt data. */
+ template <typename set_t>
+ bool collect_coverage (set_t *glyphs) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.collect_coverage (glyphs);
+ case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.collect_coverage (glyphs);
+ case 4: return u.format4.collect_coverage (glyphs);
+#endif
+ default:return false;
+ }
+ }
+
+ template <typename IterableOut,
+ hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
+ case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
+ case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
+#endif
+ default:return ;
+ }
+ }
+
+ struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+ {
+ static constexpr bool is_sorted_iterator = true;
+ iter_t (const Coverage &c_ = Null (Coverage))
+ {
+ hb_memset (this, 0, sizeof (*this));
+ format = c_.u.format;
+ switch (format)
+ {
+ case 1: u.format1.init (c_.u.format1); return;
+ case 2: u.format2.init (c_.u.format2); return;
+#ifndef HB_NO_BEYOND_64K
+ case 3: u.format3.init (c_.u.format3); return;
+ case 4: u.format4.init (c_.u.format4); return;
+#endif
+ default: return;
+ }
+ }
+ bool __more__ () const
+ {
+ switch (format)
+ {
+ case 1: return u.format1.__more__ ();
+ case 2: return u.format2.__more__ ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.__more__ ();
+ case 4: return u.format4.__more__ ();
+#endif
+ default:return false;
+ }
+ }
+ void __next__ ()
+ {
+ switch (format)
+ {
+ case 1: u.format1.__next__ (); break;
+ case 2: u.format2.__next__ (); break;
+#ifndef HB_NO_BEYOND_64K
+ case 3: u.format3.__next__ (); break;
+ case 4: u.format4.__next__ (); break;
+#endif
+ default: break;
+ }
+ }
+ typedef hb_codepoint_t __item_t__;
+ __item_t__ __item__ () const { return get_glyph (); }
+
+ hb_codepoint_t get_glyph () const
+ {
+ switch (format)
+ {
+ case 1: return u.format1.get_glyph ();
+ case 2: return u.format2.get_glyph ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_glyph ();
+ case 4: return u.format4.get_glyph ();
+#endif
+ default:return 0;
+ }
+ }
+ bool operator != (const iter_t& o) const
+ {
+ if (unlikely (format != o.format)) return true;
+ switch (format)
+ {
+ case 1: return u.format1 != o.u.format1;
+ case 2: return u.format2 != o.u.format2;
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3 != o.u.format3;
+ case 4: return u.format4 != o.u.format4;
+#endif
+ 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;
+#ifndef HB_NO_BEYOND_64K
+ case 3: it.u.format3 = u.format3.__end__ (); break;
+ case 4: it.u.format4 = u.format4.__end__ (); break;
+#endif
+ default: break;
+ }
+ return it;
+ }
+
+ private:
+ unsigned int format;
+ union {
+#ifndef HB_NO_BEYOND_64K
+ CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
+ CoverageFormat1_3<MediumTypes>::iter_t format3;
+#endif
+ CoverageFormat2_4<SmallTypes>::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
+ CoverageFormat1_3<SmallTypes>::iter_t format1;
+ } u;
+ };
+ iter_t iter () const { return iter_t (*this); }
+};
+
+template<typename Iterator>
+static inline void
+Coverage_serialize (hb_serialize_context_t *c,
+ Iterator it)
+{ c->start_embed<Coverage> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH
diff --git a/src/OT/Layout/Common/CoverageFormat1.hh b/src/OT/Layout/Common/CoverageFormat1.hh
new file mode 100644
index 000000000..5d68e3d15
--- /dev/null
+++ b/src/OT/Layout/Common/CoverageFormat1.hh
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+#define NOT_COVERED ((unsigned int) -1)
+
+template <typename Types>
+struct CoverageFormat1_3
+{
+ friend struct Coverage;
+
+ protected:
+ HBUINT16 coverageFormat; /* Format identifier--format = 1 */
+ SortedArray16Of<typename Types::HBGlyphID>
+ glyphArray; /* Array of GlyphIDs--in numerical order */
+ public:
+ DEFINE_SIZE_ARRAY (4, glyphArray);
+
+ private:
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (glyphArray.sanitize (c));
+ }
+
+ unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ unsigned int i;
+ glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
+ return i;
+ }
+
+ unsigned get_population () const
+ {
+ return glyphArray.len;
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (glyphArray.serialize (c, glyphs));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_coverage (g) != NOT_COVERED)
+ return true;
+ return false;
+ }
+
+ for (const auto& g : glyphArray.as_array ())
+ if (glyphs->has (g))
+ return true;
+ return false;
+ }
+ bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ { return glyphs->has (glyphArray[index]); }
+
+ template <typename IterableOut,
+ hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+ {
+ unsigned count = glyphArray.len;
+ for (unsigned i = 0; i < count; i++)
+ if (glyphs.has (glyphArray[i]))
+ intersect_glyphs << glyphArray[i];
+ }
+
+ template <typename set_t>
+ bool collect_coverage (set_t *glyphs) const
+ { return glyphs->add_sorted_array (glyphArray.as_array ()); }
+
+ public:
+ /* Older compilers need this to be public. */
+ struct iter_t
+ {
+ void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; }
+ bool __more__ () const { return i < c->glyphArray.len; }
+ void __next__ () { i++; }
+ hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
+ bool operator != (const iter_t& o) const
+ { 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_3 *c;
+ unsigned int i;
+ };
+ private:
+};
+
+}
+}
+}
+
+#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
diff --git a/src/OT/Layout/Common/CoverageFormat2.hh b/src/OT/Layout/Common/CoverageFormat2.hh
new file mode 100644
index 000000000..d7fcc3520
--- /dev/null
+++ b/src/OT/Layout/Common/CoverageFormat2.hh
@@ -0,0 +1,232 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+
+#include "RangeRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct CoverageFormat2_4
+{
+ friend struct Coverage;
+
+ protected:
+ HBUINT16 coverageFormat; /* Format identifier--format = 2 */
+ SortedArray16Of<RangeRecord<Types>>
+ rangeRecord; /* Array of glyph ranges--ordered by
+ * Start GlyphID. rangeCount entries
+ * long */
+ public:
+ DEFINE_SIZE_ARRAY (4, rangeRecord);
+
+ private:
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (rangeRecord.sanitize (c));
+ }
+
+ unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ const RangeRecord<Types> &range = rangeRecord.bsearch (glyph_id);
+ return likely (range.first <= range.last)
+ ? (unsigned int) range.value + (glyph_id - range.first)
+ : NOT_COVERED;
+ }
+
+ unsigned get_population () const
+ {
+ typename Types::large_int ret = 0;
+ for (const auto &r : rangeRecord)
+ ret += r.get_population ();
+ return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
+ unsigned num_ranges = 0;
+ hb_codepoint_t last = (hb_codepoint_t) -2;
+ for (auto g: glyphs)
+ {
+ if (last + 1 != g)
+ num_ranges++;
+ last = g;
+ }
+
+ if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
+ if (!num_ranges) return_trace (true);
+
+ unsigned count = 0;
+ unsigned range = (unsigned) -1;
+ last = (hb_codepoint_t) -2;
+ for (auto g: glyphs)
+ {
+ if (last + 1 != g)
+ {
+ range++;
+ rangeRecord[range].first = g;
+ rangeRecord[range].value = count;
+ }
+ rangeRecord[range].last = g;
+ last = g;
+ count++;
+ }
+
+ return_trace (true);
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_coverage (g) != NOT_COVERED)
+ return true;
+ return false;
+ }
+
+ return hb_any (+ hb_iter (rangeRecord)
+ | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
+ }
+ bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ {
+ auto *range = rangeRecord.as_array ().bsearch (index);
+ if (range)
+ return range->intersects (*glyphs);
+ return false;
+ }
+
+ template <typename IterableOut,
+ hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+ void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+ {
+ /* Break out of loop for overlapping, broken, tables,
+ * to avoid fuzzer timouts. */
+ hb_codepoint_t last = 0;
+ for (const auto& range : rangeRecord)
+ {
+ if (unlikely (range.first < last))
+ break;
+ last = range.last;
+ for (hb_codepoint_t g = range.first - 1;
+ glyphs.next (&g) && g <= last;)
+ intersect_glyphs << g;
+ }
+ }
+
+ template <typename set_t>
+ bool collect_coverage (set_t *glyphs) const
+ {
+ for (const auto& range: rangeRecord)
+ if (unlikely (!range.collect_coverage (glyphs)))
+ return false;
+ return true;
+ }
+
+ public:
+ /* Older compilers need this to be public. */
+ struct iter_t
+ {
+ void init (const CoverageFormat2_4 &c_)
+ {
+ c = &c_;
+ coverage = 0;
+ i = 0;
+ j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
+ if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
+ {
+ /* Broken table. Skip. */
+ i = c->rangeRecord.len;
+ j = 0;
+ }
+ }
+ bool __more__ () const { return i < c->rangeRecord.len; }
+ void __next__ ()
+ {
+ if (j >= c->rangeRecord[i].last)
+ {
+ i++;
+ if (__more__ ())
+ {
+ unsigned int old = coverage;
+ j = c->rangeRecord[i].first;
+ coverage = c->rangeRecord[i].value;
+ if (unlikely (coverage != old + 1))
+ {
+ /* Broken table. Skip. Important to avoid DoS.
+ * Also, our callers depend on coverage being
+ * consecutive and monotonically increasing,
+ * ie. iota(). */
+ i = c->rangeRecord.len;
+ j = 0;
+ return;
+ }
+ }
+ else
+ j = 0;
+ return;
+ }
+ coverage++;
+ j++;
+ }
+ hb_codepoint_t get_glyph () const { return j; }
+ bool operator != (const iter_t& o) const
+ { 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_4 *c;
+ unsigned int i, coverage;
+ hb_codepoint_t j;
+ };
+ private:
+};
+
+}
+}
+}
+
+#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
diff --git a/src/OT/Layout/Common/RangeRecord.hh b/src/OT/Layout/Common/RangeRecord.hh
new file mode 100644
index 000000000..a62629fad
--- /dev/null
+++ b/src/OT/Layout/Common/RangeRecord.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
+#define OT_LAYOUT_COMMON_RANGERECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct RangeRecord
+{
+ typename Types::HBGlyphID first; /* First GlyphID in the range */
+ typename Types::HBGlyphID last; /* Last GlyphID in the range */
+ HBUINT16 value; /* Value */
+
+ DEFINE_SIZE_STATIC (2 + 2 * Types::size);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ int cmp (hb_codepoint_t g) const
+ { return g < first ? -1 : g <= last ? 0 : +1; }
+
+ unsigned get_population () const
+ {
+ if (unlikely (last < first)) return 0;
+ return (last - first + 1);
+ }
+
+ bool intersects (const hb_set_t &glyphs) const
+ { return glyphs.intersects (first, last); }
+
+ template <typename set_t>
+ bool collect_coverage (set_t *glyphs) const
+ { return glyphs->add_range (first, last); }
+};
+
+}
+}
+}
+
+// TODO(garretrieger): This was previously implemented using
+// DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9);
+// but that only works when there is only a single namespace level.
+// The macro should probably be fixed so it can work in this situation.
+extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9];
+template <typename Spec>
+struct Null<OT::Layout::Common::RangeRecord<Spec>> {
+ static OT::Layout::Common::RangeRecord<Spec> const & get_null () {
+ return *reinterpret_cast<const OT::Layout::Common::RangeRecord<Spec> *> (_hb_Null_OT_RangeRecord);
+ }
+};
+
+
+#endif // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
diff --git a/src/OT/Layout/GPOS/Anchor.hh b/src/OT/Layout/GPOS/Anchor.hh
new file mode 100644
index 000000000..49e76e775
--- /dev/null
+++ b/src/OT/Layout/GPOS/Anchor.hh
@@ -0,0 +1,83 @@
+#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 (u.format3.subset (c));
+ 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/src/OT/Layout/GPOS/AnchorFormat1.hh b/src/OT/Layout/GPOS/AnchorFormat1.hh
new file mode 100644
index 000000000..738cc31bb
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/AnchorFormat2.hh b/src/OT/Layout/GPOS/AnchorFormat2.hh
new file mode 100644
index 000000000..70b4d19f5
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/OT/Layout/GPOS/AnchorFormat3.hh
new file mode 100644
index 000000000..2e30ab33c
--- /dev/null
+++ b/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -0,0 +1,100 @@
+#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);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (unlikely (!c->serializer->embed (format))) return_trace (false);
+ if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
+ if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
+
+ unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ if (c->plan->layout_variation_idx_delta_map->has (x_varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
+
+ unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ if (c->plan->layout_variation_idx_delta_map->has (y_varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
+
+ if (c->plan->all_axes_pinned)
+ return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+ if (!c->serializer->embed (xDeviceTable)) return_trace (false);
+ if (!c->serializer->embed (yDeviceTable)) return_trace (false);
+
+ out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
+ out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
+ return_trace (out);
+ }
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ {
+ (this+xDeviceTable).collect_variation_indices (c);
+ (this+yDeviceTable).collect_variation_indices (c);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
diff --git a/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/OT/Layout/GPOS/AnchorMatrix.hh
new file mode 100644
index 000000000..c442efa1e
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/ChainContextPos.hh b/src/OT/Layout/GPOS/ChainContextPos.hh
new file mode 100644
index 000000000..d551ac2a2
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/Common.hh b/src/OT/Layout/GPOS/Common.hh
new file mode 100644
index 000000000..408197454
--- /dev/null
+++ b/src/OT/Layout/GPOS/Common.hh
@@ -0,0 +1,33 @@
+#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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned);
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_COMMON_HH
diff --git a/src/OT/Layout/GPOS/ContextPos.hh b/src/OT/Layout/GPOS/ContextPos.hh
new file mode 100644
index 000000000..2a01eaa3a
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/CursivePos.hh b/src/OT/Layout/GPOS/CursivePos.hh
new file mode 100644
index 000000000..c105cfb09
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/OT/Layout/GPOS/CursivePosFormat1.hh
new file mode 100644
index 000000000..7f58fac8b
--- /dev/null
+++ b/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -0,0 +1,301 @@
+#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;
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "cursive attaching glyph at %d to glyph at %d",
+ i, j);
+ }
+
+ buffer->unsafe_to_break (i, j + 1);
+ 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;
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+ pos[parent].y_offset = 0;
+ else
+ pos[parent].x_offset = 0;
+ }
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "cursive attached glyph at %d to glyph at %d",
+ i, j);
+ }
+
+ 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/src/OT/Layout/GPOS/ExtensionPos.hh b/src/OT/Layout/GPOS/ExtensionPos.hh
new file mode 100644
index 000000000..d1808adab
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/GPOS.hh b/src/OT/Layout/GPOS/GPOS.hh
new file mode 100644
index 000000000..9493ec987
--- /dev/null
+++ b/src/OT/Layout/GPOS/GPOS.hh
@@ -0,0 +1,171 @@
+#ifndef OT_LAYOUT_GPOS_GPOS_HH
+#define OT_LAYOUT_GPOS_GPOS_HH
+
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "PosLookup.hh"
+
+namespace OT {
+
+using Layout::GPOS_impl::PosLookup;
+
+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 = PosLookup;
+
+ 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);
+ return GSUBGPOS::subset<PosLookup> (&l);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (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
+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_GPOS_HH */
diff --git a/src/OT/Layout/GPOS/LigatureArray.hh b/src/OT/Layout/GPOS/LigatureArray.hh
new file mode 100644
index 000000000..a2d807cc3
--- /dev/null
+++ b/src/OT/Layout/GPOS/LigatureArray.hh
@@ -0,0 +1,56 @@
+#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH
+#define OT_LAYOUT_GPOS_LIGATUREARRAY_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);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */
diff --git a/src/OT/Layout/GPOS/MarkArray.hh b/src/OT/Layout/GPOS/MarkArray.hh
new file mode 100644
index 000000000..cb5e8b268
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkArray.hh
@@ -0,0 +1,128 @@
+#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);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "attaching mark glyph at %d to glyph at %d",
+ c->buffer->idx, glyph_pos);
+ }
+
+ 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;
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "attached mark glyph at %d to glyph at %d",
+ c->buffer->idx, glyph_pos);
+ }
+
+ 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);
+ }
+};
+
+HB_INTERNAL inline
+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/src/OT/Layout/GPOS/MarkBasePos.hh b/src/OT/Layout/GPOS/MarkBasePos.hh
new file mode 100644
index 000000000..edf7099c0
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkBasePos.hh
@@ -0,0 +1,41 @@
+#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_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ MarkBasePosFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
new file mode 100644
index 000000000..ebb8c31c6
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -0,0 +1,219 @@
+#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. */
+
+template <typename Types>
+struct MarkBasePosFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ markCoverage; /* Offset to MarkCoverage table--from
+ * beginning of MarkBasePos subtable */
+ typename Types::template OffsetTo<Coverage>
+ baseCoverage; /* Offset to BaseCoverage table--from
+ * beginning of MarkBasePos subtable */
+ HBUINT16 classCount; /* Number of classes defined for marks */
+ typename Types::template OffsetTo<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkBasePos subtable */
+ typename Types::template OffsetTo<BaseArray>
+ baseArray; /* Offset to BaseArray table--from
+ * beginning of MarkBasePos subtable */
+
+ public:
+ DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+ 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_multiplied (&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/src/OT/Layout/GPOS/MarkLigPos.hh b/src/OT/Layout/GPOS/MarkLigPos.hh
new file mode 100644
index 000000000..09152fd87
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkLigPos.hh
@@ -0,0 +1,41 @@
+#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_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ MarkLigPosFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
new file mode 100644
index 000000000..1a8021237
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -0,0 +1,206 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+
+#include "LigatureArray.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct MarkLigPosFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ markCoverage; /* Offset to Mark Coverage table--from
+ * beginning of MarkLigPos subtable */
+ typename Types::template OffsetTo<Coverage>
+ ligatureCoverage; /* Offset to Ligature Coverage
+ * table--from beginning of MarkLigPos
+ * subtable */
+ HBUINT16 classCount; /* Number of defined mark classes */
+ typename Types::template OffsetTo<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkLigPos subtable */
+ typename Types::template OffsetTo<LigatureArray>
+ ligatureArray; /* Offset to LigatureArray table--from
+ * beginning of MarkLigPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+ 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/src/OT/Layout/GPOS/MarkMarkPos.hh b/src/OT/Layout/GPOS/MarkMarkPos.hh
new file mode 100644
index 000000000..4118fc304
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkMarkPos.hh
@@ -0,0 +1,42 @@
+#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_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ MarkMarkPosFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
new file mode 100644
index 000000000..fbcebb804
--- /dev/null
+++ b/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -0,0 +1,228 @@
+#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. */
+
+template <typename Types>
+struct MarkMarkPosFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ mark1Coverage; /* Offset to Combining Mark1 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ typename Types::template OffsetTo<Coverage>
+ mark2Coverage; /* Offset to Combining Mark2 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ HBUINT16 classCount; /* Number of defined mark classes */
+ typename Types::template OffsetTo<MarkArray>
+ mark1Array; /* Offset to Mark1Array table--from
+ * beginning of MarkMarkPos subtable */
+ typename Types::template OffsetTo<Mark2Array>
+ mark2Array; /* Offset to Mark2Array table--from
+ * beginning of MarkMarkPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+ 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 & ~(uint32_t)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/src/OT/Layout/GPOS/MarkRecord.hh b/src/OT/Layout/GPOS/MarkRecord.hh
new file mode 100644
index 000000000..a7d489d2a
--- /dev/null
+++ b/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;
+
+ public:
+ 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/src/OT/Layout/GPOS/PairPos.hh b/src/OT/Layout/GPOS/PairPos.hh
new file mode 100644
index 000000000..9823768cb
--- /dev/null
+++ b/src/OT/Layout/GPOS/PairPos.hh
@@ -0,0 +1,46 @@
+#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_3<SmallTypes> format1;
+ PairPosFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+ PairPosFormat1_3<MediumTypes> format3;
+ PairPosFormat2_4<MediumTypes> format4;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOS_HH
diff --git a/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/OT/Layout/GPOS/PairPosFormat1.hh
new file mode 100644
index 000000000..9c9b26888
--- /dev/null
+++ b/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -0,0 +1,219 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+
+#include "PairSet.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairPosFormat1_3
+{
+ using PairSet = GPOS_impl::PairSet<Types>;
+ using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
+
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<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) */
+ Array16Of<typename Types::template OffsetTo<PairSet>>
+ pairSet; /* Array of PairSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (8 + Types::size, 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 ();
+ typename 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
+ {
+ auto &cov = this+coverage;
+
+ if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
+ {
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ {
+ unsigned i = cov.get_coverage (g);
+ if ((this+pairSet[i]).intersects (glyphs, valueFormat))
+ return true;
+ }
+ return false;
+ }
+
+ return
+ + hb_zip (cov, pairSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second)
+ | hb_map ([glyphs, this] (const typename Types::template OffsetTo<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;
+ }
+
+ if (c->plan->all_axes_pinned)
+ {
+ out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
+ out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+ }
+
+ 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 typename Types::template OffsetTo<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 auto & _ :
+ + hb_zip (this+coverage, pairSet)
+ | hb_filter (glyphset, hb_first)
+ | hb_map (hb_second)
+ )
+ {
+ const PairSet& set = (this + _);
+ const PairValueRecord *record = &set.firstPairValueRecord;
+
+ unsigned count = set.len;
+ for (unsigned i = 0; i < count; 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);
+ }
+
+ if (format1 == valueFormat[0] && format2 == valueFormat[1])
+ break;
+ }
+
+ return hb_pair (format1, format2);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
diff --git a/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/OT/Layout/GPOS/PairPosFormat2.hh
new file mode 100644
index 000000000..9c87ac2b0
--- /dev/null
+++ b/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -0,0 +1,351 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+template <typename Types>
+struct PairPosFormat2_4
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 2 */
+ typename Types::template OffsetTo<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) */
+ typename Types::template OffsetTo<ClassDef>
+ classDef1; /* Offset to ClassDef table--from
+ * beginning of PairPos subtable--for
+ * the first glyph of the pair */
+ typename Types::template OffsetTo<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 (10 + 3 * Types::size, 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:
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "try kerning glyphs at %d,%d",
+ c->buffer->idx, skippy_iter.idx);
+ }
+
+ 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]);
+
+ if (applied_first || applied_second)
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, skippy_iter.idx);
+ }
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "tried kerning glyphs at %d,%d",
+ c->buffer->idx, 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);
+
+ if (len2)
+ {
+ skippy_iter.idx++;
+ // https://github.com/harfbuzz/harfbuzz/issues/3824
+ // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+ buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
+ }
+
+ buffer->idx = skippy_iter.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;
+
+ if (c->plan->all_axes_pinned)
+ {
+ out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
+ out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
+ }
+
+ 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, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map);
+ valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_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 record_size = len1 + len2;
+
+ 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) * record_size;
+ format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
+ format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+ }
+
+ if (format1 == valueFormat1 && format2 == valueFormat2)
+ break;
+ }
+
+ return hb_pair (format1, format2);
+ }
+};
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
diff --git a/src/OT/Layout/GPOS/PairSet.hh b/src/OT/Layout/GPOS/PairSet.hh
new file mode 100644
index 000000000..a318f3991
--- /dev/null
+++ b/src/OT/Layout/GPOS/PairSet.hh
@@ -0,0 +1,203 @@
+#ifndef OT_LAYOUT_GPOS_PAIRSET_HH
+#define OT_LAYOUT_GPOS_PAIRSET_HH
+
+#include "PairValueRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairSet
+{
+ template <typename Types2>
+ friend struct PairPosFormat1_3;
+
+ using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
+
+ protected:
+ HBUINT16 len; /* Number of PairValueRecords */
+ PairValueRecord firstPairValueRecord;
+ /* Array of PairValueRecords--ordered
+ * by GlyphID of the second glyph */
+ public:
+ DEFINE_SIZE_MIN (2);
+
+ 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));
+ }
+
+ 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)
+ {
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "try kerning glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
+ 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)
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "tried kerning glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
+ if (applied_first || applied_second)
+ buffer->unsafe_to_break (buffer->idx, pos + 1);
+
+ if (len2)
+ {
+ pos++;
+ // https://github.com/harfbuzz/harfbuzz/issues/3824
+ // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+ buffer->unsafe_to_break (buffer->idx, pos + 1);
+ }
+
+ 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);
+
+ typename PairValueRecord::context_t context =
+ {
+ this,
+ valueFormats,
+ newFormats,
+ len1,
+ &glyph_map,
+ c->plan->layout_variation_idx_delta_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);
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRSET_HH
diff --git a/src/OT/Layout/GPOS/PairValueRecord.hh b/src/OT/Layout/GPOS/PairValueRecord.hh
new file mode 100644
index 000000000..322247776
--- /dev/null
+++ b/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -0,0 +1,99 @@
+#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairValueRecord
+{
+ template <typename Types2>
+ friend struct PairSet;
+
+ protected:
+ typename Types::HBGlyphID
+ 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 (Types::size, values);
+
+ 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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_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_delta_map);
+ closure->valueFormats[1].copy_values (s,
+ closure->newFormats[1],
+ closure->base,
+ &values[closure->len1],
+ closure->layout_variation_idx_delta_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 ()];
+ }
+};
+
+
+}
+}
+}
+
+#endif // OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
diff --git a/src/OT/Layout/GPOS/PosLookup.hh b/src/OT/Layout/GPOS/PosLookup.hh
new file mode 100644
index 000000000..c4e57bb54
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/PosLookupSubTable.hh b/src/OT/Layout/GPOS/PosLookupSubTable.hh
new file mode 100644
index 000000000..c19fbc323
--- /dev/null
+++ b/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/src/OT/Layout/GPOS/SinglePos.hh b/src/OT/Layout/GPOS/SinglePos.hh
new file mode 100644
index 000000000..6dce3e634
--- /dev/null
+++ b/src/OT/Layout/GPOS/SinglePos.hh
@@ -0,0 +1,100 @@
+#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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned)
+ {
+ if (unlikely (!c->extend_min (u.format))) return;
+ unsigned format = 2;
+ ValueFormat new_format = src->get_value_format ();
+
+ if (all_axes_pinned)
+ new_format = new_format.drop_device_table_flags ();
+
+ if (glyph_val_iter_pairs)
+ format = get_format (glyph_val_iter_pairs);
+
+ u.format = format;
+ switch (u.format) {
+ case 1: u.format1.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_delta_map);
+ return;
+ case 2: u.format2.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_delta_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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ bool all_axes_pinned)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */
diff --git a/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/OT/Layout/GPOS/SinglePosFormat1.hh
new file mode 100644
index 000000000..b4c9fc3db
--- /dev/null
+++ b/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -0,0 +1,156 @@
+#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;
+
+ hb_set_t intersection;
+ (this+coverage).intersect_set (*c->glyph_set, intersection);
+ if (!intersection) 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);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioning glyph at %d",
+ c->buffer->idx);
+ }
+
+ valueFormat.apply_value (c, this, values, buffer->cur_pos());
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioned glyph at %d",
+ c->buffer->idx);
+ }
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ bool
+ position_single (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t gid,
+ hb_glyph_position_t &pos) const
+ {
+ unsigned int index = (this+coverage).get_coverage (gid);
+ if (likely (index == NOT_COVERED)) return false;
+
+ /* This is ugly... */
+ hb_buffer_t buffer;
+ buffer.props.direction = direction;
+ OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+ valueFormat.apply_value (&c, this, values, pos);
+ return 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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_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_delta_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;
+
+ hb_set_t intersection;
+ (this+coverage).intersect_set (glyphset, intersection);
+
+ auto it =
+ + hb_iter (intersection)
+ | 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_delta_map, c->plan->all_axes_pinned);
+ return_trace (ret);
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/OT/Layout/GPOS/SinglePosFormat2.hh
new file mode 100644
index 000000000..c77951156
--- /dev/null
+++ b/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -0,0 +1,176 @@
+#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 (unlikely (index >= valueCount)) return_trace (false);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioning glyph at %d",
+ c->buffer->idx);
+ }
+
+ valueFormat.apply_value (c, this,
+ &values[index * valueFormat.get_len ()],
+ buffer->cur_pos());
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioned glyph at %d",
+ c->buffer->idx);
+ }
+
+ buffer->idx++;
+ return_trace (true);
+ }
+
+ bool
+ position_single (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t gid,
+ hb_glyph_position_t &pos) const
+ {
+ unsigned int index = (this+coverage).get_coverage (gid);
+ if (likely (index == NOT_COVERED)) return false;
+ if (unlikely (index >= valueCount)) return false;
+
+ /* This is ugly... */
+ hb_buffer_t buffer;
+ buffer.props.direction = direction;
+ OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+ valueFormat.apply_value (&c, this,
+ &values[index * valueFormat.get_len ()],
+ pos);
+ return 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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_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_delta_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_delta_map, c->plan->all_axes_pinned);
+ return_trace (ret);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */
diff --git a/src/OT/Layout/GPOS/ValueFormat.hh b/src/OT/Layout/GPOS/ValueFormat.hh
new file mode 100644
index 000000000..26a40f01a
--- /dev/null
+++ b/src/OT/Layout/GPOS/ValueFormat.hh
@@ -0,0 +1,394 @@
+#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; }
+
+ hb_vector_t<unsigned> get_device_table_indices () const {
+ unsigned i = 0;
+ hb_vector_t<unsigned> result;
+ unsigned format = *this;
+
+ if (format & xPlacement) i++;
+ if (format & yPlacement) i++;
+ if (format & xAdvance) i++;
+ if (format & yAdvance) i++;
+
+ if (format & xPlaDevice) result.push (i++);
+ if (format & yPlaDevice) result.push (i++);
+ if (format & xAdvDevice) result.push (i++);
+ if (format & yAdvDevice) result.push (i++);
+
+ return result;
+ }
+
+ 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_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
+ {
+ unsigned int format = *this;
+ if (!format) return;
+
+ HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
+ if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
+ if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
+ if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
+ if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
+
+ if (format & xPlaDevice)
+ {
+ add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
+ }
+
+ if (format & yPlaDevice)
+ {
+ add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
+ }
+
+ if (format & xAdvDevice)
+ {
+ add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
+ }
+
+ if (format & yAdvDevice)
+ {
+ add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
+ copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
+ }
+ }
+
+ HBINT16* 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 nullptr;
+ return reinterpret_cast<HBINT16 *> (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);
+ i++;
+ }
+
+ if (format & ValueFormat::yPlaDevice)
+ {
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
+ i++;
+ }
+
+ if (format & ValueFormat::xAdvDevice)
+ {
+
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
+ i++;
+ }
+
+ if (format & ValueFormat::yAdvDevice)
+ {
+
+ (base + get_device (&(values[i]))).collect_variation_indices (c);
+ i++;
+ }
+ }
+
+ unsigned drop_device_table_flags () const
+ {
+ unsigned format = *this;
+ for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
+ format = format & ~flag;
+
+ return format;
+ }
+
+ 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);
+ }
+
+ void add_delta_to_value (HBINT16 *value,
+ const void *base,
+ const Value *src_value,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
+ {
+ if (!value) return;
+ unsigned varidx = (base + get_device (src_value)).get_variation_index ();
+ hb_pair_t<unsigned, int> *varidx_delta;
+ if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
+
+ *value += hb_second (*varidx_delta);
+ }
+
+ bool copy_device (hb_serialize_context_t *c, const void *base,
+ const Value *src_value,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+ unsigned int new_format, Flags flag) const
+ {
+ // Filter by new format.
+ if (!(new_format & flag)) return true;
+
+ 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_delta_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/src/OT/Layout/GSUB/AlternateSet.hh b/src/OT/Layout/GSUB/AlternateSet.hh
new file mode 100644
index 000000000..6c50c9717
--- /dev/null
+++ b/src/OT/Layout/GSUB/AlternateSet.hh
@@ -0,0 +1,126 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH
+#define OT_LAYOUT_GSUB_ALTERNATESET_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct AlternateSet
+{
+ protected:
+ Array16Of<typename Types::HBGlyphID>
+ alternates; /* Array of alternate GlyphIDs--in
+ * arbitrary order */
+ public:
+ DEFINE_SIZE_ARRAY (2, alternates);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (alternates.sanitize (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return hb_any (alternates, glyphs); }
+
+ void closure (hb_closure_context_t *c) const
+ { c->output->add_array (alternates.arrayZ, alternates.len); }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { c->output->add_array (alternates.arrayZ, alternates.len); }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int count = alternates.len;
+
+ if (unlikely (!count)) return_trace (false);
+
+ hb_mask_t glyph_mask = c->buffer->cur().mask;
+ hb_mask_t lookup_mask = c->lookup_mask;
+
+ /* Note: This breaks badly if two features enabled this lookup together. */
+ unsigned int shift = hb_ctz (lookup_mask);
+ unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+ /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
+ if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
+ {
+ /* Maybe we can do better than unsafe-to-break all; but since we are
+ * changing random state, it would be hard to track that. Good 'nough. */
+ c->buffer->unsafe_to_break (0, c->buffer->len);
+ alt_index = c->random_number () % count + 1;
+ }
+
+ if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (alternate substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph (alternates[alt_index - 1]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (alternate substitution)",
+ c->buffer->idx - 1);
+ }
+
+ return_trace (true);
+ }
+
+ unsigned
+ get_alternates (unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ {
+ if (alternates.len && alternate_count)
+ {
+ + alternates.as_array ().sub_array (start_offset, alternate_count)
+ | hb_sink (hb_array (alternate_glyphs, *alternate_count))
+ ;
+ }
+ return alternates.len;
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator alts)
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (alternates.serialize (c, alts));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto it =
+ + hb_iter (alternates)
+ | hb_filter (glyphset)
+ | hb_map (glyph_map)
+ ;
+
+ auto *out = c->serializer->start_embed (*this);
+ return_trace (out->serialize (c->serializer, it) &&
+ out->alternates);
+ }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */
diff --git a/src/OT/Layout/GSUB/AlternateSubst.hh b/src/OT/Layout/GSUB/AlternateSubst.hh
new file mode 100644
index 000000000..9d7cd6fdd
--- /dev/null
+++ b/src/OT/Layout/GSUB/AlternateSubst.hh
@@ -0,0 +1,62 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+
+#include "AlternateSubstFormat1.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct AlternateSubst
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ AlternateSubstFormat1_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ AlternateSubstFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
+ /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+ * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
+ bool serialize (hb_serialize_context_t *c,
+ hb_sorted_array_t<const HBGlyphID16> glyphs,
+ hb_array_t<const unsigned int> alternate_len_list,
+ hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format = format;
+ switch (u.format) {
+ case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
+ default:return_trace (false);
+ }
+ }
+
+ /* TODO subset() should choose format. */
+
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_ALTERNATESUBST_HH */
diff --git a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
new file mode 100644
index 000000000..adec65d58
--- /dev/null
+++ b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
@@ -0,0 +1,128 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+
+#include "AlternateSet.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct AlternateSubstFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Array16Of<typename Types::template OffsetTo<AlternateSet<Types>>>
+ alternateSet; /* Array of AlternateSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ bool may_have_non_1to1 () const
+ { return false; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ + hb_zip (this+coverage, alternateSet)
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ + hb_zip (this+coverage, alternateSet)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const AlternateSet<Types> &_) { _.collect_glyphs (c); })
+ ;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+ unsigned
+ get_glyph_alternates (hb_codepoint_t gid,
+ unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ { return (this+alternateSet[(this+coverage).get_coverage (gid)])
+ .get_alternates (start_offset, alternate_count, alternate_glyphs); }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ return_trace ((this+alternateSet[index]).apply (c));
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ hb_sorted_array_t<const HBGlyphID16> glyphs,
+ hb_array_t<const unsigned int> alternate_len_list,
+ hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
+ for (unsigned int i = 0; i < glyphs.length; i++)
+ {
+ unsigned int alternate_len = alternate_len_list[i];
+ if (unlikely (!alternateSet[i]
+ .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
+ return_trace (false);
+ alternate_glyphs_list += alternate_len;
+ }
+ return_trace (coverage.serialize_serialize (c, glyphs));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ + hb_zip (this+coverage, alternateSet)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+ out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+ return_trace (bool (new_coverage));
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/ChainContextSubst.hh b/src/OT/Layout/GSUB/ChainContextSubst.hh
new file mode 100644
index 000000000..08fd779f7
--- /dev/null
+++ b/src/OT/Layout/GSUB/ChainContextSubst.hh
@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ChainContextSubst : ChainContext {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH */
diff --git a/src/OT/Layout/GSUB/Common.hh b/src/OT/Layout/GSUB/Common.hh
new file mode 100644
index 000000000..968bba048
--- /dev/null
+++ b/src/OT/Layout/GSUB/Common.hh
@@ -0,0 +1,21 @@
+#ifndef OT_LAYOUT_GSUB_COMMON_HH
+#define OT_LAYOUT_GSUB_COMMON_HH
+
+#include "../../../hb-serialize.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
+
+template<typename Iterator>
+static void SingleSubst_serialize (hb_serialize_context_t *c,
+ Iterator it);
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_COMMON_HH */
diff --git a/src/OT/Layout/GSUB/ContextSubst.hh b/src/OT/Layout/GSUB/ContextSubst.hh
new file mode 100644
index 000000000..9f8cb46b5
--- /dev/null
+++ b/src/OT/Layout/GSUB/ContextSubst.hh
@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ContextSubst : Context {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_CONTEXTSUBST_HH */
diff --git a/src/OT/Layout/GSUB/ExtensionSubst.hh b/src/OT/Layout/GSUB/ExtensionSubst.hh
new file mode 100644
index 000000000..831a7dfa2
--- /dev/null
+++ b/src/OT/Layout/GSUB/ExtensionSubst.hh
@@ -0,0 +1,22 @@
+#ifndef OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+#define OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ExtensionSubst : Extension<ExtensionSubst>
+{
+ typedef struct SubstLookupSubTable SubTable;
+ bool is_reverse () const;
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_EXTENSIONSUBST_HH */
diff --git a/src/OT/Layout/GSUB/GSUB.hh b/src/OT/Layout/GSUB/GSUB.hh
new file mode 100644
index 000000000..900cf603e
--- /dev/null
+++ b/src/OT/Layout/GSUB/GSUB.hh
@@ -0,0 +1,61 @@
+#ifndef OT_LAYOUT_GSUB_GSUB_HH
+#define OT_LAYOUT_GSUB_GSUB_HH
+
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "SubstLookup.hh"
+
+namespace OT {
+
+using Layout::GSUB_impl::SubstLookup;
+
+namespace Layout {
+
+/*
+ * GSUB -- Glyph Substitution
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/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
+ { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ hb_subset_layout_context_t l (c, tableTag);
+ return GSUBGPOS::subset<SubstLookup> (&l);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
+ }
+
+ HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+ hb_face_t *face) const;
+
+ void closure_lookups (hb_face_t *face,
+ const hb_set_t *glyphs,
+ hb_set_t *lookup_indexes /* IN/OUT */) const
+ { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
+
+ typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
+};
+
+
+}
+
+struct GSUB_accelerator_t : Layout::GSUB::accelerator_t {
+ GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {}
+};
+
+
+}
+
+#endif /* OT_LAYOUT_GSUB_GSUB_HH */
diff --git a/src/OT/Layout/GSUB/Ligature.hh b/src/OT/Layout/GSUB/Ligature.hh
new file mode 100644
index 000000000..cdb35f525
--- /dev/null
+++ b/src/OT/Layout/GSUB/Ligature.hh
@@ -0,0 +1,187 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURE_HH
+#define OT_LAYOUT_GSUB_LIGATURE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct Ligature
+{
+ protected:
+ typename Types::HBGlyphID
+ ligGlyph; /* GlyphID of ligature to substitute */
+ HeadlessArrayOf<typename Types::HBGlyphID>
+ component; /* Array of component GlyphIDs--start
+ * with the second component--ordered
+ * in writing direction */
+ public:
+ DEFINE_SIZE_ARRAY (Types::size + 2, component);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return hb_all (component, glyphs); }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ if (!intersects (c->glyphs)) return;
+ c->output->add (ligGlyph);
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ c->input->add_array (component.arrayZ, component.get_length ());
+ c->output->add (ligGlyph);
+ }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ {
+ if (c->len != component.lenP1)
+ return false;
+
+ for (unsigned int i = 1; i < c->len; i++)
+ if (likely (c->glyphs[i] != component[i]))
+ return false;
+
+ return true;
+ }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int count = component.lenP1;
+
+ if (unlikely (!count)) return_trace (false);
+
+ /* Special-case to make it in-place and not consider this
+ * as a "ligated" substitution. */
+ if (unlikely (count == 1))
+ {
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (ligature substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph (ligGlyph);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (ligature substitution)",
+ c->buffer->idx - 1);
+ }
+
+ return_trace (true);
+ }
+
+ unsigned int total_component_count = 0;
+
+ unsigned int match_end = 0;
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+
+ if (likely (!match_input (c, count,
+ &component[1],
+ match_glyph,
+ nullptr,
+ &match_end,
+ match_positions,
+ &total_component_count)))
+ {
+ c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
+ return_trace (false);
+ }
+
+ unsigned pos = 0;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ unsigned delta = c->buffer->sync_so_far ();
+
+ pos = c->buffer->idx;
+
+ char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+ char *p = buf;
+
+ match_end += delta;
+ for (unsigned i = 0; i < count; i++)
+ {
+ match_positions[i] += delta;
+ if (i)
+ *p++ = ',';
+ snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
+ p += strlen(p);
+ }
+
+ c->buffer->message (c->font,
+ "ligating glyphs at %s",
+ buf);
+ }
+
+ ligate_input (c,
+ count,
+ match_positions,
+ match_end,
+ ligGlyph,
+ total_component_count);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "ligated glyph at %d",
+ pos);
+ }
+
+ return_trace (true);
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c,
+ hb_codepoint_t ligature,
+ Iterator components /* Starting from second */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ ligGlyph = ligature;
+ if (unlikely (!component.serialize (c, components))) return_trace (false);
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
+ // Ensure Coverage table is always packed after this.
+ c->serializer->add_virtual_link (coverage_idx);
+
+ auto it =
+ + hb_iter (component)
+ | hb_map (glyph_map)
+ ;
+
+ auto *out = c->serializer->start_embed (*this);
+ return_trace (out->serialize (c->serializer,
+ glyph_map[ligGlyph],
+ it)); }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_LIGATURE_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSet.hh b/src/OT/Layout/GSUB/LigatureSet.hh
new file mode 100644
index 000000000..637cec713
--- /dev/null
+++ b/src/OT/Layout/GSUB/LigatureSet.hh
@@ -0,0 +1,119 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH
+#define OT_LAYOUT_GSUB_LIGATURESET_HH
+
+#include "Common.hh"
+#include "Ligature.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct LigatureSet
+{
+ protected:
+ Array16OfOffset16To<Ligature<Types>>
+ ligature; /* Array LigatureSet tables
+ * ordered by preference */
+ public:
+ DEFINE_SIZE_ARRAY (2, ligature);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (ligature.sanitize (c, this));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
+ | hb_any
+ ;
+ }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
+ ;
+ }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
+ ;
+ }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ {
+ return
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
+ | hb_any
+ ;
+ }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int num_ligs = ligature.len;
+ for (unsigned int i = 0; i < num_ligs; i++)
+ {
+ const auto &lig = this+ligature[i];
+ if (lig.apply (c)) return_trace (true);
+ }
+
+ return_trace (false);
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ hb_array_t<const HBGlyphID16> ligatures,
+ hb_array_t<const unsigned int> component_count_list,
+ hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
+ for (unsigned int i = 0; i < ligatures.length; i++)
+ {
+ unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
+ if (unlikely (!ligature[i].serialize_serialize (c,
+ ligatures[i],
+ component_list.sub_array (0, component_count))))
+ return_trace (false);
+ component_list += component_count;
+ }
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ + hb_iter (ligature)
+ | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
+ | hb_drain
+ ;
+
+ if (bool (out->ligature))
+ // Ensure Coverage table is always packed after this.
+ c->serializer->add_virtual_link (coverage_idx);
+
+ return_trace (bool (out->ligature));
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSubst.hh b/src/OT/Layout/GSUB/LigatureSubst.hh
new file mode 100644
index 000000000..7ba19e844
--- /dev/null
+++ b/src/OT/Layout/GSUB/LigatureSubst.hh
@@ -0,0 +1,71 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBST_HH
+
+#include "Common.hh"
+#include "LigatureSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct LigatureSubst
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ LigatureSubstFormat1_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ LigatureSubstFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
+ /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should
+ * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t
+ * instead. */
+ bool serialize (hb_serialize_context_t *c,
+ hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+ hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+ hb_array_t<const HBGlyphID16> ligatures_list,
+ hb_array_t<const unsigned int> component_count_list,
+ hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format = format;
+ switch (u.format) {
+ case 1: return_trace (u.format1.serialize (c,
+ first_glyphs,
+ ligature_per_first_glyph_count_list,
+ ligatures_list,
+ component_count_list,
+ component_list));
+ default:return_trace (false);
+ }
+ }
+
+ /* TODO subset() should choose format. */
+
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
new file mode 100644
index 000000000..32b642c38
--- /dev/null
+++ b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -0,0 +1,166 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "LigatureSet.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct LigatureSubstFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Array16Of<typename Types::template OffsetTo<LigatureSet<Types>>>
+ ligatureSet; /* Array LigatureSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ return
+ + hb_zip (this+coverage, ligatureSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second)
+ | hb_map ([this, glyphs] (const typename Types::template OffsetTo<LigatureSet<Types>> &_)
+ { return (this+_).intersects (glyphs); })
+ | hb_any
+ ;
+ }
+
+ bool may_have_non_1to1 () const
+ { return true; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ + hb_zip (this+coverage, ligatureSet)
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const LigatureSet<Types> &_) { _.closure (c); })
+ ;
+
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+ + hb_zip (this+coverage, ligatureSet)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const LigatureSet<Types> &_) { _.collect_glyphs (c); })
+ ;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ {
+ unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+ if (likely (index == NOT_COVERED)) return false;
+
+ const auto &lig_set = this+ligatureSet[index];
+ return lig_set.would_apply (c);
+ }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const auto &lig_set = this+ligatureSet[index];
+ return_trace (lig_set.apply (c));
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+ hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+ hb_array_t<const HBGlyphID16> ligatures_list,
+ hb_array_t<const unsigned int> component_count_list,
+ hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
+ for (unsigned int i = 0; i < first_glyphs.length; i++)
+ {
+ unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
+ if (unlikely (!ligatureSet[i]
+ .serialize_serialize (c,
+ ligatures_list.sub_array (0, ligature_count),
+ component_count_list.sub_array (0, ligature_count),
+ component_list))) return_trace (false);
+ ligatures_list += ligature_count;
+ component_count_list += ligature_count;
+ }
+ return_trace (coverage.serialize_serialize (c, first_glyphs));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ // Due to a bug in some older versions of windows 7 the Coverage table must be
+ // packed after the LigatureSet and Ligature tables, so serialize Coverage first
+ // which places it last in the packed order.
+ hb_set_t new_coverage;
+ + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
+ | hb_filter (glyphset, hb_first)
+ | hb_filter ([&] (const LigatureSet<Types>& _) {
+ return _.intersects (&glyphset);
+ }, hb_second)
+ | hb_map (hb_first)
+ | hb_sink (new_coverage);
+
+ if (!c->serializer->push<Coverage> ()
+ ->serialize (c->serializer,
+ + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
+ {
+ c->serializer->pop_discard ();
+ return_trace (false);
+ }
+
+ unsigned coverage_idx = c->serializer->pop_pack ();
+ c->serializer->add_link (out->coverage, coverage_idx);
+
+ + hb_zip (this+coverage, ligatureSet)
+ | hb_filter (new_coverage, hb_first)
+ | hb_map (hb_second)
+ // to ensure that the repacker always orders the coverage table after the LigatureSet
+ // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
+ // the coverage table object idx is passed down to facilitate this.
+ | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
+ ;
+
+ return_trace (bool (new_coverage));
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/MultipleSubst.hh b/src/OT/Layout/GSUB/MultipleSubst.hh
new file mode 100644
index 000000000..95710ed2b
--- /dev/null
+++ b/src/OT/Layout/GSUB/MultipleSubst.hh
@@ -0,0 +1,62 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+
+#include "Common.hh"
+#include "MultipleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct MultipleSubst
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ MultipleSubstFormat1_2<SmallTypes> format1;
+#ifndef HB_NO_BEYOND_64K
+ MultipleSubstFormat1_2<MediumTypes> format2;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator it)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format = format;
+ switch (u.format) {
+ case 1: return_trace (u.format1.serialize (c, it));
+ default:return_trace (false);
+ }
+ }
+
+ /* TODO subset() should choose format. */
+
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
new file mode 100644
index 000000000..3b4bd1169
--- /dev/null
+++ b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
@@ -0,0 +1,130 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "Sequence.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct MultipleSubstFormat1_2
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Array16Of<typename Types::template OffsetTo<Sequence<Types>>>
+ sequence; /* Array of Sequence tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (4 + Types::size, sequence);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ bool may_have_non_1to1 () const
+ { return true; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ + hb_zip (this+coverage, sequence)
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const Sequence<Types> &_) { _.closure (c); })
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ + hb_zip (this+coverage, sequence)
+ | hb_map (hb_second)
+ | hb_map (hb_add (this))
+ | hb_apply ([c] (const Sequence<Types> &_) { _.collect_glyphs (c); })
+ ;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ return_trace ((this+sequence[index]).apply (c));
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator it)
+ {
+ TRACE_SERIALIZE (this);
+ auto sequences =
+ + it
+ | hb_map (hb_second)
+ ;
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
+ if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false);
+
+ for (auto& pair : hb_zip (sequences, sequence))
+ {
+ if (unlikely (!pair.second
+ .serialize_serialize (c, pair.first)))
+ return_trace (false);
+ }
+
+ return_trace (coverage.serialize_serialize (c, glyphs));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ + hb_zip (this+coverage, sequence)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
+ | hb_map (hb_first)
+ | hb_map (glyph_map)
+ | hb_sink (new_coverage)
+ ;
+ out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+ return_trace (bool (new_coverage));
+ }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
new file mode 100644
index 000000000..48e208efb
--- /dev/null
+++ b/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
@@ -0,0 +1,36 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+
+#include "Common.hh"
+#include "ReverseChainSingleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ReverseChainSingleSubst
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ ReverseChainSingleSubstFormat1 format1;
+ } u;
+
+ public:
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+ case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+ default:return_trace (c->default_return_value ());
+ }
+ }
+};
+
+}
+}
+}
+
+#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
new file mode 100644
index 000000000..a23e92028
--- /dev/null
+++ b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -0,0 +1,244 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ReverseChainSingleSubstFormat1
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ Offset16To<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of table */
+ Array16OfOffset16To<Coverage>
+ backtrack; /* Array of coverage tables
+ * in backtracking sequence, in glyph
+ * sequence order */
+ Array16OfOffset16To<Coverage>
+ lookaheadX; /* Array of coverage tables
+ * in lookahead sequence, in glyph
+ * sequence order */
+ Array16Of<HBGlyphID16>
+ substituteX; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_MIN (10);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
+ return_trace (false);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+ if (!lookahead.sanitize (c, this))
+ return_trace (false);
+ const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+ return_trace (substitute.sanitize (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ if (!(this+coverage).intersects (glyphs))
+ return false;
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+
+ unsigned int count;
+
+ count = backtrack.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+backtrack[i]).intersects (glyphs))
+ return false;
+
+ count = lookahead.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+lookahead[i]).intersects (glyphs))
+ return false;
+
+ return true;
+ }
+
+ bool may_have_non_1to1 () const
+ { return false; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ if (!intersects (c->glyphs)) return;
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+ const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+ + hb_zip (this+coverage, substitute)
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map (hb_second)
+ | hb_sink (c->output)
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+ unsigned int count;
+
+ count = backtrack.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+ count = lookahead.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
+
+ const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+ count = substitute.len;
+ c->output->add_array (substitute.arrayZ, substitute.len);
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+ return_trace (false); /* No chaining to this type */
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+ const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+ if (unlikely (index >= substitute.len)) return_trace (false);
+
+ unsigned int start_index = 0, end_index = 0;
+ if (match_backtrack (c,
+ backtrack.len, (HBUINT16 *) backtrack.arrayZ,
+ match_coverage, this,
+ &start_index) &&
+ match_lookahead (c,
+ lookahead.len, (HBUINT16 *) lookahead.arrayZ,
+ match_coverage, this,
+ c->buffer->idx + 1, &end_index))
+ {
+ c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replacing glyph at %d (reverse chaining substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph_inplace (substitute[index]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (reverse chaining substitution)",
+ c->buffer->idx);
+ }
+
+ /* Note: We DON'T decrease buffer->idx. The main loop does it
+ * for us. This is useful for preventing surprises if someone
+ * calls us through a Context lookup. */
+ return_trace (true);
+ }
+ else
+ {
+ c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
+ return_trace (false);
+ }
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
+
+ if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+ return_trace (false);
+
+ for (auto& offset : it) {
+ auto *o = out->serialize_append (c->serializer);
+ if (unlikely (!o) || !o->serialize_subset (c, offset, this))
+ return_trace (false);
+ }
+
+ return_trace (true);
+ }
+
+ template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
+ hb_requires (hb_is_iterator (BacktrackIterator)),
+ hb_requires (hb_is_iterator (LookaheadIterator))>
+ bool serialize (hb_subset_context_t *c,
+ Iterator coverage_subst_iter,
+ BacktrackIterator backtrack_iter,
+ LookaheadIterator lookahead_iter) const
+ {
+ TRACE_SERIALIZE (this);
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->check_success (out))) return_trace (false);
+ if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+ if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
+
+ if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
+ if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
+
+ auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
+ auto substitutes =
+ + coverage_subst_iter
+ | hb_map (hb_second)
+ ;
+
+ auto glyphs =
+ + coverage_subst_iter
+ | hb_map_retains_sorting (hb_first)
+ ;
+ if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
+ return_trace (false);
+
+ if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
+ return_trace (false);
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+ const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+ auto it =
+ + hb_zip (this+coverage, substitute)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter (glyphset, hb_second)
+ | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
+ { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+ ;
+
+ return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
+ }
+};
+
+}
+}
+}
+
+#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/Sequence.hh b/src/OT/Layout/GSUB/Sequence.hh
new file mode 100644
index 000000000..e2190078b
--- /dev/null
+++ b/src/OT/Layout/GSUB/Sequence.hh
@@ -0,0 +1,165 @@
+#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
+#define OT_LAYOUT_GSUB_SEQUENCE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct Sequence
+{
+ protected:
+ Array16Of<typename Types::HBGlyphID>
+ substitute; /* String of GlyphIDs to substitute */
+ public:
+ DEFINE_SIZE_ARRAY (2, substitute);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (substitute.sanitize (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return hb_all (substitute, glyphs); }
+
+ void closure (hb_closure_context_t *c) const
+ { c->output->add_array (substitute.arrayZ, substitute.len); }
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ { c->output->add_array (substitute.arrayZ, substitute.len); }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int count = substitute.len;
+
+ /* Special-case to make it in-place and not consider this
+ * as a "multiplied" substitution. */
+ if (unlikely (count == 1))
+ {
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph (substitute.arrayZ[0]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (multiple subtitution)",
+ c->buffer->idx - 1);
+ }
+
+ return_trace (true);
+ }
+ /* Spec disallows this, but Uniscribe allows it.
+ * https://github.com/harfbuzz/harfbuzz/issues/253 */
+ else if (unlikely (count == 0))
+ {
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "deleting glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
+ c->buffer->delete_glyph ();
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "deleted glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
+ return_trace (true);
+ }
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "multiplying glyph at %d",
+ c->buffer->idx);
+ }
+
+ unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+ unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ /* If is attached to a ligature, don't disturb that.
+ * https://github.com/harfbuzz/harfbuzz/issues/3069 */
+ if (!lig_id)
+ _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+ c->output_glyph_for_component (substitute.arrayZ[i], klass);
+ }
+ c->buffer->skip_glyph ();
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+
+ char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+ char *p = buf;
+
+ for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
+ {
+ if (buf < p)
+ *p++ = ',';
+ snprintf (p, sizeof(buf) - (p - buf), "%u", i);
+ p += strlen(p);
+ }
+
+ c->buffer->message (c->font,
+ "multiplied glyphs at %s",
+ buf);
+ }
+
+ return_trace (true);
+ }
+
+ template <typename Iterator,
+ hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator subst)
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (substitute.serialize (c, subst));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ if (!intersects (&glyphset)) return_trace (false);
+
+ auto it =
+ + hb_iter (substitute)
+ | hb_map (glyph_map)
+ ;
+
+ auto *out = c->serializer->start_embed (*this);
+ return_trace (out->serialize (c->serializer, it));
+ }
+};
+
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubst.hh b/src/OT/Layout/GSUB/SingleSubst.hh
new file mode 100644
index 000000000..7da810316
--- /dev/null
+++ b/src/OT/Layout/GSUB/SingleSubst.hh
@@ -0,0 +1,103 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBST_HH
+#define OT_LAYOUT_GSUB_SINGLESUBST_HH
+
+#include "Common.hh"
+#include "SingleSubstFormat1.hh"
+#include "SingleSubstFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SingleSubst
+{
+ protected:
+ union {
+ HBUINT16 format; /* Format identifier */
+ SingleSubstFormat1_3<SmallTypes> format1;
+ SingleSubstFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+ SingleSubstFormat1_3<MediumTypes> format3;
+ SingleSubstFormat2_4<MediumTypes> format4;
+#endif
+ } 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)...));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator,
+ const hb_codepoint_pair_t))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned format = 2;
+ unsigned delta = 0;
+ if (glyphs)
+ {
+ format = 1;
+ hb_codepoint_t mask = 0xFFFFu;
+
+#ifndef HB_NO_BEYOND_64K
+ if (+ glyphs
+ | hb_map_retains_sorting (hb_first)
+ | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
+ {
+ format += 2;
+ mask = 0xFFFFFFu;
+ }
+#endif
+
+ auto get_delta = [=] (hb_codepoint_pair_t _)
+ { return (unsigned) (_.second - _.first) & mask; };
+ delta = get_delta (*glyphs);
+ if (!hb_all (++(+glyphs), delta, get_delta)) format += 1;
+ }
+
+ u.format = format;
+ switch (u.format) {
+ case 1: return_trace (u.format1.serialize (c,
+ + glyphs
+ | hb_map_retains_sorting (hb_first),
+ delta));
+ case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.serialize (c,
+ + glyphs
+ | hb_map_retains_sorting (hb_first),
+ delta));
+ case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
+ default:return_trace (false);
+ }
+ }
+};
+
+template<typename Iterator>
+static void
+SingleSubst_serialize (hb_serialize_context_t *c,
+ Iterator it)
+{ c->start_embed<SingleSubst> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/OT/Layout/GSUB/SingleSubstFormat1.hh
new file mode 100644
index 000000000..1be21b98b
--- /dev/null
+++ b/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -0,0 +1,168 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct SingleSubstFormat1_3
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 1 */
+ typename Types::template OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ typename Types::HBUINT
+ deltaGlyphID; /* Add to original GlyphID to get
+ * substitute GlyphID, modulo 0x10000 */
+
+ public:
+ DEFINE_SIZE_STATIC (2 + 2 * Types::size);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+ }
+
+ hb_codepoint_t get_mask () const
+ { return (1 << (8 * Types::size)) - 1; }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ bool may_have_non_1to1 () const
+ { return false; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ /* Help fuzzer avoid this function as much. */
+ unsigned pop = (this+coverage).get_population ();
+ if (pop >= mask)
+ return;
+
+ hb_set_t intersection;
+ (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
+
+ /* In degenerate fuzzer-found fonts, but not real fonts,
+ * this table can keep adding new glyphs in each round of closure.
+ * Refuse to close-over, if it maps glyph range to overlapping range. */
+ hb_codepoint_t min_before = intersection.get_min ();
+ hb_codepoint_t max_before = intersection.get_max ();
+ hb_codepoint_t min_after = (min_before + d) & mask;
+ hb_codepoint_t max_after = (max_before + d) & mask;
+ if (intersection.get_population () == max_before - min_before + 1 &&
+ ((min_before <= min_after && min_after <= max_before) ||
+ (min_before <= max_after && max_after <= max_before)))
+ return;
+
+ + hb_iter (intersection)
+ | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
+ | hb_sink (c->output)
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ + hb_iter (this+coverage)
+ | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
+ | hb_sink (c->output)
+ ;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ glyph_id = (glyph_id + d) & mask;
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (single substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph (glyph_id);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (single substitution)",
+ c->buffer->idx - 1);
+ }
+
+ return_trace (true);
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator glyphs,
+ unsigned delta)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+ c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ hb_set_t intersection;
+ (this+coverage).intersect_set (glyphset, intersection);
+
+ auto it =
+ + hb_iter (intersection)
+ | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
+ return hb_codepoint_pair_t (g,
+ (g + d) & mask); })
+ | hb_filter (glyphset, hb_second)
+ | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
+ { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+ ;
+
+ bool ret = bool (it);
+ SingleSubst_serialize (c->serializer, it);
+ return_trace (ret);
+ }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/OT/Layout/GSUB/SingleSubstFormat2.hh
new file mode 100644
index 000000000..01df71452
--- /dev/null
+++ b/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -0,0 +1,151 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct SingleSubstFormat2_4
+{
+ protected:
+ HBUINT16 format; /* Format identifier--format = 2 */
+ typename Types::template OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Array16Of<typename Types::HBGlyphID>
+ substitute; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+
+ public:
+ DEFINE_SIZE_ARRAY (4 + Types::size, substitute);
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
+ bool may_have_non_1to1 () const
+ { return false; }
+
+ void closure (hb_closure_context_t *c) const
+ {
+ auto &cov = this+coverage;
+ auto &glyph_set = c->parent_active_glyphs ();
+
+ if (substitute.len > glyph_set.get_population () * 4)
+ {
+ for (auto g : glyph_set)
+ {
+ unsigned i = cov.get_coverage (g);
+ if (i == NOT_COVERED || i >= substitute.len)
+ continue;
+ c->output->add (substitute.arrayZ[i]);
+ }
+
+ return;
+ }
+
+ + hb_zip (cov, substitute)
+ | hb_filter (glyph_set, hb_first)
+ | hb_map (hb_second)
+ | hb_sink (c->output)
+ ;
+ }
+
+ void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+ void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ + hb_zip (this+coverage, substitute)
+ | hb_map (hb_second)
+ | hb_sink (c->output)
+ ;
+ }
+
+ const Coverage &get_coverage () const { return this+coverage; }
+
+ bool would_apply (hb_would_apply_context_t *c) const
+ { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ if (unlikely (index >= substitute.len)) return_trace (false);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (single substitution)",
+ c->buffer->idx);
+ }
+
+ c->replace_glyph (substitute[index]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (single substitution)",
+ c->buffer->idx - 1);
+ }
+
+ return_trace (true);
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_source_of (Iterator,
+ hb_codepoint_pair_t))>
+ bool serialize (hb_serialize_context_t *c,
+ Iterator it)
+ {
+ TRACE_SERIALIZE (this);
+ auto substitutes =
+ + it
+ | hb_map (hb_second)
+ ;
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
+ if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto it =
+ + hb_zip (this+coverage, substitute)
+ | hb_filter (glyphset, hb_first)
+ | hb_filter (glyphset, hb_second)
+ | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const typename Types::HBGlyphID &> p) -> hb_codepoint_pair_t
+ { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+ ;
+
+ bool ret = bool (it);
+ SingleSubst_serialize (c->serializer, it);
+ return_trace (ret);
+ }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH */
diff --git a/src/OT/Layout/GSUB/SubstLookup.hh b/src/OT/Layout/GSUB/SubstLookup.hh
new file mode 100644
index 000000000..d49dcc0e0
--- /dev/null
+++ b/src/OT/Layout/GSUB/SubstLookup.hh
@@ -0,0 +1,220 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+
+#include "Common.hh"
+#include "SubstLookupSubTable.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SubstLookup : Lookup
+{
+ using SubTable = SubstLookupSubTable;
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ { return Lookup::sanitize<SubTable> (c); }
+
+ const SubTable& get_subtable (unsigned int i) const
+ { return Lookup::get_subtable<SubTable> (i); }
+
+ static inline bool lookup_type_is_reverse (unsigned int lookup_type)
+ { return lookup_type == SubTable::ReverseChainSingle; }
+
+ bool is_reverse () const
+ {
+ unsigned int type = get_type ();
+ if (unlikely (type == SubTable::Extension))
+ return get_subtable (0).u.extension.is_reverse ();
+ return lookup_type_is_reverse (type);
+ }
+
+ bool may_have_non_1to1 () const
+ {
+ hb_have_non_1to1_context_t c;
+ return dispatch (&c);
+ }
+
+ bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ return_trace (dispatch (c));
+ }
+
+ bool intersects (const hb_set_t *glyphs) const
+ {
+ hb_intersects_context_t c (glyphs);
+ return dispatch (&c);
+ }
+
+ hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
+ {
+ if (!c->should_visit_lookup (this_index))
+ return hb_closure_context_t::default_return_value ();
+
+ c->set_recurse_func (dispatch_closure_recurse_func);
+
+ hb_closure_context_t::return_t ret = dispatch (c);
+
+ c->flush ();
+
+ return ret;
+ }
+
+ hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+ {
+ if (c->is_lookup_visited (this_index))
+ return hb_closure_lookups_context_t::default_return_value ();
+
+ c->set_lookup_visited (this_index);
+ if (!intersects (c->glyphs))
+ {
+ c->set_lookup_inactive (this_index);
+ return hb_closure_lookups_context_t::default_return_value ();
+ }
+
+ hb_closure_lookups_context_t::return_t ret = dispatch (c);
+ return ret;
+ }
+
+ hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+ return dispatch (c);
+ }
+
+ template <typename set_t>
+ void collect_coverage (set_t *glyphs) const
+ {
+ hb_collect_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
+ }
+
+ bool would_apply (hb_would_apply_context_t *c,
+ const hb_ot_layout_lookup_accelerator_t *accel) const
+ {
+ if (unlikely (!c->len)) return false;
+ if (!accel->may_have (c->glyphs[0])) return false;
+ return dispatch (c);
+ }
+
+ template<typename Glyphs, typename Substitutes,
+ hb_requires (hb_is_sorted_source_of (Glyphs,
+ const hb_codepoint_t) &&
+ hb_is_source_of (Substitutes,
+ const hb_codepoint_t))>
+ bool serialize_single (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Glyphs glyphs,
+ Substitutes substitutes)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
+ if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
+ {
+ c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+ return_trace (true);
+ }
+ c->pop_discard ();
+ return_trace (false);
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_sorted_iterator (Iterator))>
+ bool serialize (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Iterator it)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
+ if (c->push<SubTable> ()->u.multiple.
+ serialize (c, it))
+ {
+ c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+ return_trace (true);
+ }
+ c->pop_discard ();
+ return_trace (false);
+ }
+
+ bool serialize_alternate (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ hb_sorted_array_t<const HBGlyphID16> glyphs,
+ hb_array_t<const unsigned int> alternate_len_list,
+ hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
+
+ if (c->push<SubTable> ()->u.alternate.
+ serialize (c,
+ glyphs,
+ alternate_len_list,
+ alternate_glyphs_list))
+ {
+ c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+ return_trace (true);
+ }
+ c->pop_discard ();
+ return_trace (false);
+ }
+
+ bool serialize_ligature (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+ hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+ hb_array_t<const HBGlyphID16> ligatures_list,
+ hb_array_t<const unsigned int> component_count_list,
+ hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
+ if (c->push<SubTable> ()->u.ligature.
+ serialize (c,
+ first_glyphs,
+ ligature_per_first_glyph_count_list,
+ ligatures_list,
+ component_count_list,
+ component_list))
+ {
+ c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+ return_trace (true);
+ }
+ c->pop_discard ();
+ return_trace (false);
+ }
+
+ template <typename context_t>
+ static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+ static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
+
+ static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
+ {
+ if (!c->should_visit_lookup (lookup_index))
+ return hb_empty_t ();
+
+ hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
+
+ /* While in theory we should flush here, it will cause timeouts because a recursive
+ * lookup can keep growing the glyph set. Skip, and outer loop will retry up to
+ * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
+ //c->flush ();
+
+ return ret;
+ }
+
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
+
+ bool subset (hb_subset_context_t *c) const
+ { return Lookup::subset<SubTable> (c); }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */
diff --git a/src/OT/Layout/GSUB/SubstLookupSubTable.hh b/src/OT/Layout/GSUB/SubstLookupSubTable.hh
new file mode 100644
index 000000000..a525fba03
--- /dev/null
+++ b/src/OT/Layout/GSUB/SubstLookupSubTable.hh
@@ -0,0 +1,77 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+
+#include "Common.hh"
+#include "SingleSubst.hh"
+#include "MultipleSubst.hh"
+#include "AlternateSubst.hh"
+#include "LigatureSubst.hh"
+#include "ContextSubst.hh"
+#include "ChainContextSubst.hh"
+#include "ExtensionSubst.hh"
+#include "ReverseChainSingleSubst.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SubstLookupSubTable
+{
+ friend struct ::OT::Lookup;
+ friend struct SubstLookup;
+
+ protected:
+ union {
+ SingleSubst single;
+ MultipleSubst multiple;
+ AlternateSubst alternate;
+ LigatureSubst ligature;
+ ContextSubst context;
+ ChainContextSubst chainContext;
+ ExtensionSubst extension;
+ ReverseChainSingleSubst reverseChainContextSingle;
+ } u;
+ public:
+ DEFINE_SIZE_MIN (0);
+
+ enum Type {
+ Single = 1,
+ Multiple = 2,
+ Alternate = 3,
+ Ligature = 4,
+ Context = 5,
+ ChainContext = 6,
+ Extension = 7,
+ ReverseChainSingle = 8
+ };
+
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
+ {
+ TRACE_DISPATCH (this, lookup_type);
+ switch (lookup_type) {
+ case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
+ case Multiple: return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
+ case Alternate: return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
+ case Ligature: return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
+ case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
+ case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
+ case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
+ case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
+ default: return_trace (c->default_return_value ());
+ }
+ }
+
+ bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+ {
+ hb_intersects_context_t c (glyphs);
+ return dispatch (&c, lookup_type);
+ }
+};
+
+
+}
+}
+}
+
+#endif /* HB_OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH */
diff --git a/src/OT/Layout/types.hh b/src/OT/Layout/types.hh
new file mode 100644
index 000000000..6a43403e9
--- /dev/null
+++ b/src/OT/Layout/types.hh
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_TYPES_HH
+#define OT_LAYOUT_TYPES_HH
+
+namespace OT {
+namespace Layout {
+
+struct SmallTypes {
+ static constexpr unsigned size = 2;
+ using large_int = uint32_t;
+ using HBUINT = HBUINT16;
+ using HBGlyphID = HBGlyphID16;
+ using Offset = Offset16;
+ template <typename Type, bool has_null=true>
+ using OffsetTo = OT::Offset16To<Type, has_null>;
+ template <typename Type>
+ using ArrayOf = OT::Array16Of<Type>;
+ template <typename Type>
+ using SortedArrayOf = OT::SortedArray16Of<Type>;
+};
+
+struct MediumTypes {
+ static constexpr unsigned size = 3;
+ using large_int = uint64_t;
+ using HBUINT = HBUINT24;
+ using HBGlyphID = HBGlyphID24;
+ using Offset = Offset24;
+ template <typename Type, bool has_null=true>
+ using OffsetTo = OT::Offset24To<Type, has_null>;
+ template <typename Type>
+ using ArrayOf = OT::Array24Of<Type>;
+ template <typename Type>
+ using SortedArrayOf = OT::SortedArray24Of<Type>;
+};
+
+}
+}
+
+#endif /* OT_LAYOUT_TYPES_HH */
diff --git a/src/OT/glyf/CompositeGlyph.hh b/src/OT/glyf/CompositeGlyph.hh
new file mode 100644
index 000000000..edf8cd879
--- /dev/null
+++ b/src/OT/glyf/CompositeGlyph.hh
@@ -0,0 +1,369 @@
+#ifndef OT_GLYF_COMPOSITEGLYPH_HH
+#define OT_GLYF_COMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+#include "composite-iter.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,
+#ifndef HB_NO_BEYOND_64K
+ GID_IS_24BIT = 0x2000
+#endif
+ };
+
+ public:
+ unsigned int get_size () const
+ {
+ unsigned int size = min_size;
+ /* glyphIndex is 24bit instead of 16bit */
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
+#endif
+ /* 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 auto *p = &StructAfter<const HBUINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ p += HBGlyphID24::static_size;
+ else
+#endif
+ p += HBGlyphID16::static_size;
+ 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);
+ }
+ }
+ }
+
+ unsigned compile_with_deltas (const contour_point_t &p_delta,
+ char *out) const
+ {
+ const HBINT8 *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ p += HBGlyphID24::static_size;
+ else
+#endif
+ p += HBGlyphID16::static_size;
+
+ unsigned len = get_size ();
+ unsigned len_before_val = (const char *)p - (const char *)this;
+ if (flags & ARG_1_AND_2_ARE_WORDS)
+ {
+ // no overflow, copy and update value with deltas
+ hb_memcpy (out, this, len);
+
+ const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
+ HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
+ o[0] = px[0] + roundf (p_delta.x);
+ o[1] = px[1] + roundf (p_delta.y);
+ }
+ else
+ {
+ int new_x = p[0] + roundf (p_delta.x);
+ int new_y = p[1] + roundf (p_delta.y);
+ if (new_x <= 127 && new_x >= -128 &&
+ new_y <= 127 && new_y >= -128)
+ {
+ hb_memcpy (out, this, len);
+ HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
+ o[0] = new_x;
+ o[1] = new_y;
+ }
+ else
+ {
+ // int8 overflows after deltas applied
+ hb_memcpy (out, this, len_before_val);
+
+ //update flags
+ CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
+ o->flags = flags | ARG_1_AND_2_ARE_WORDS;
+ out += len_before_val;
+
+ HBINT16 new_value;
+ new_value = new_x;
+ hb_memcpy (out, &new_value, HBINT16::static_size);
+ out += HBINT16::static_size;
+
+ new_value = new_y;
+ hb_memcpy (out, &new_value, HBINT16::static_size);
+ out += HBINT16::static_size;
+
+ hb_memcpy (out, p+2, len - len_before_val - 2);
+ len += 2;
+ }
+ }
+ return len;
+ }
+
+ 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;
+
+ const auto *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ p += HBGlyphID24::static_size;
+ else
+#endif
+ p += HBGlyphID16::static_size;
+ int tx, ty;
+ 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:
+ hb_codepoint_t get_gid () const
+ {
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ return StructAfter<const HBGlyphID24> (flags);
+ else
+#endif
+ return StructAfter<const HBGlyphID16> (flags);
+ }
+ void set_gid (hb_codepoint_t gid)
+ {
+#ifndef HB_NO_BEYOND_64K
+ if (flags & GID_IS_24BIT)
+ StructAfter<HBGlyphID24> (flags) = gid;
+ else
+#endif
+ /* TODO assert? */
+ StructAfter<HBGlyphID16> (flags) = gid;
+ }
+
+ protected:
+ HBUINT16 flags;
+ HBUINT24 pad;
+ public:
+ DEFINE_SIZE_MIN (4);
+};
+
+using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
+
+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 ();
+ }
+
+ bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
+ const contour_point_vector_t &deltas,
+ hb_bytes_t &dest_bytes /* OUT */)
+ {
+ if (source_bytes.length <= GlyphHeader::static_size ||
+ header.numberOfContours != -1)
+ {
+ dest_bytes = hb_bytes_t ();
+ return true;
+ }
+
+ unsigned source_len = source_bytes.length - GlyphHeader::static_size;
+
+ /* try to allocate more memories than source glyph bytes
+ * in case that there might be an overflow for int8 value
+ * and we would need to use int16 instead */
+ char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
+ if (unlikely (!o)) return false;
+
+ const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
+ auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
+
+ char *p = o;
+ unsigned i = 0, source_comp_len = 0;
+ for (const auto &component : it)
+ {
+ /* last 4 points in deltas are phantom points and should not be included */
+ if (i >= deltas.length - 4) return false;
+
+ unsigned comp_len = component.get_size ();
+ if (component.is_anchored ())
+ {
+ hb_memcpy (p, &component, comp_len);
+ p += comp_len;
+ }
+ else
+ {
+ unsigned new_len = component.compile_with_deltas (deltas[i], p);
+ p += new_len;
+ }
+ i++;
+ source_comp_len += comp_len;
+ }
+
+ //copy instructions if any
+ if (source_len > source_comp_len)
+ {
+ unsigned instr_len = source_len - source_comp_len;
+ hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
+ p += instr_len;
+ }
+
+ unsigned len = p - o;
+ dest_bytes = hb_bytes_t (o, len);
+ return true;
+ }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_COMPOSITEGLYPH_HH */
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh
new file mode 100644
index 000000000..b7215b017
--- /dev/null
+++ b/src/OT/glyf/Glyph.hh
@@ -0,0 +1,463 @@
+#ifndef OT_GLYF_GLYPH_HH
+#define OT_GLYF_GLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+#include "GlyphHeader.hh"
+#include "SimpleGlyph.hh"
+#include "CompositeGlyph.hh"
+#include "VarCompositeGlyph.hh"
+#include "coord-setter.hh"
+
+
+namespace OT {
+
+struct glyf_accelerator_t;
+
+namespace glyf_impl {
+
+
+#ifndef HB_GLYF_MAX_POINTS
+#define HB_GLYF_MAX_POINTS 10000
+#endif
+
+
+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, VAR_COMPOSITE };
+
+ public:
+ composite_iter_t get_composite_iterator () const
+ {
+ if (type != COMPOSITE) return composite_iter_t ();
+ return CompositeGlyph (*header, bytes).iter ();
+ }
+ var_composite_iter_t get_var_composite_iterator () const
+ {
+ if (type != VAR_COMPOSITE) return var_composite_iter_t ();
+ return VarCompositeGlyph (*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;
+ }
+ }
+
+ void update_mtx (const hb_subset_plan_t *plan,
+ int xMin, int yMax,
+ const contour_point_vector_t &all_points) const
+ {
+ hb_codepoint_t new_gid = 0;
+ if (!plan->new_gid_for_old_gid (gid, &new_gid))
+ return;
+
+ unsigned len = all_points.length;
+ float leftSideX = all_points[len - 4].x;
+ float rightSideX = all_points[len - 3].x;
+ float topSideY = all_points[len - 2].y;
+ float bottomSideY = all_points[len - 1].y;
+
+ int hori_aw = roundf (rightSideX - leftSideX);
+ if (hori_aw < 0) hori_aw = 0;
+ int lsb = roundf (xMin - leftSideX);
+ plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb));
+
+ int vert_aw = roundf (topSideY - bottomSideY);
+ if (vert_aw < 0) vert_aw = 0;
+ int tsb = roundf (topSideY - yMax);
+ plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb));
+ }
+
+ bool compile_header_bytes (const hb_subset_plan_t *plan,
+ const contour_point_vector_t &all_points,
+ hb_bytes_t &dest_bytes /* OUT */) const
+ {
+ GlyphHeader *glyph_header = nullptr;
+ if (type != EMPTY && all_points.length > 4)
+ {
+ glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
+ if (unlikely (!glyph_header)) return false;
+ }
+
+ float xMin = 0, xMax = 0;
+ float yMin = 0, yMax = 0;
+ if (all_points.length > 4)
+ {
+ xMin = xMax = all_points[0].x;
+ yMin = yMax = all_points[0].y;
+ }
+
+ for (unsigned i = 1; i < all_points.length - 4; i++)
+ {
+ float x = all_points[i].x;
+ float y = all_points[i].y;
+ xMin = hb_min (xMin, x);
+ xMax = hb_max (xMax, x);
+ yMin = hb_min (yMin, y);
+ yMax = hb_max (yMax, y);
+ }
+
+ update_mtx (plan, roundf (xMin), roundf (yMax), all_points);
+
+ /*for empty glyphs: all_points only include phantom points.
+ *just update metrics and then return */
+ if (!glyph_header)
+ return true;
+
+ glyph_header->numberOfContours = header->numberOfContours;
+ glyph_header->xMin = roundf (xMin);
+ glyph_header->yMin = roundf (yMin);
+ glyph_header->xMax = roundf (xMax);
+ glyph_header->yMax = roundf (yMax);
+
+ dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
+ return true;
+ }
+
+ bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+ hb_font_t *font,
+ const glyf_accelerator_t &glyf,
+ hb_bytes_t &dest_start, /* IN/OUT */
+ hb_bytes_t &dest_end /* OUT */)
+ {
+ contour_point_vector_t all_points, deltas;
+ if (!get_points (font, glyf, all_points, &deltas, false, false))
+ return false;
+
+ // .notdef, set type to empty so we only update metrics and don't compile bytes for
+ // it
+ if (gid == 0 &&
+ !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ type = EMPTY;
+
+ switch (type) {
+ case COMPOSITE:
+ if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
+ deltas,
+ dest_end))
+ return false;
+ break;
+ case SIMPLE:
+ if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
+ dest_end))
+ return false;
+ break;
+ default:
+ /* set empty bytes for empty glyph
+ * do not use source glyph's pointers */
+ dest_start = hb_bytes_t ();
+ dest_end = hb_bytes_t ();
+ break;
+ }
+
+ if (!compile_header_bytes (plan, all_points, dest_start))
+ {
+ dest_end.fini ();
+ return false;
+ }
+ return true;
+ }
+
+
+ /* 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 */,
+ contour_point_vector_t *deltas = nullptr, /* OUT */
+ bool shift_points_hori = true,
+ bool use_my_metrics = true,
+ bool phantom_only = false,
+ hb_array_t<int> coords = hb_array_t<int> (),
+ unsigned int depth = 0) const
+ {
+ if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+
+ if (!coords)
+ coords = hb_array (font->coords, font->num_coords);
+
+ 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 SIMPLE:
+ if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+ return false;
+ break;
+ 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;
+ }
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ {
+ for (auto &item : get_var_composite_iterator ())
+ if (unlikely (!item.get_points (points))) return false;
+ }
+#endif
+ default:
+ break;
+ }
+
+ /* Init phantom points */
+ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+ hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+ {
+ int lsb = 0;
+ int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+ (int) header->xMin - lsb : 0;
+ HB_UNUSED int tsb = 0;
+ int v_orig = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+ ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
+#else
+ 0
+#endif
+ ;
+ unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
+ unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+ glyf_accelerator.vmtx->get_advance_without_var_unscaled (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;
+ }
+
+ if (deltas != nullptr && depth == 0 && type == COMPOSITE)
+ {
+ if (unlikely (!deltas->resize (points.length))) return false;
+ deltas->copy_vector (points);
+ }
+
+#ifndef HB_NO_VAR
+ glyf_accelerator.gvar->apply_deltas_to_points (gid,
+ coords,
+ points.as_array ());
+#endif
+
+ // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
+ // with child glyphs' points
+ if (deltas != nullptr && depth == 0 && type == COMPOSITE)
+ {
+ for (unsigned i = 0 ; i < points.length; i++)
+ {
+ deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
+ deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
+ }
+ }
+
+ 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.get_gid ())
+ .get_points (font,
+ glyf_accelerator,
+ comp_points,
+ deltas,
+ shift_points_hori,
+ use_my_metrics,
+ phantom_only,
+ coords,
+ depth + 1)))
+ return false;
+
+ /* Copy phantom points from component if USE_MY_METRICS flag set */
+ if (use_my_metrics && 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.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+ if (all_points.length > HB_GLYF_MAX_POINTS)
+ return false;
+
+ comp_index++;
+ }
+
+ all_points.extend (phantoms);
+ } break;
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ {
+ contour_point_vector_t comp_points;
+ hb_array_t<contour_point_t> points_left = points.as_array ();
+ for (auto &item : get_var_composite_iterator ())
+ {
+ hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
+
+ comp_points.reset ();
+
+ coord_setter_t coord_setter (coords);
+ item.set_variations (coord_setter, record_points);
+
+ if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+ .get_points (font,
+ glyf_accelerator,
+ comp_points,
+ deltas,
+ shift_points_hori,
+ use_my_metrics,
+ phantom_only,
+ coord_setter.get_coords (),
+ depth + 1)))
+ return false;
+
+ /* Apply component transformation */
+ item.transform_points (record_points, comp_points);
+
+ /* Copy phantom points from component if USE_MY_METRICS flag set */
+ if (use_my_metrics && item.is_use_my_metrics ())
+ for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+ phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+ all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+ if (all_points.length > HB_GLYF_MAX_POINTS)
+ return false;
+
+ points_left += item.get_num_points ();
+ }
+ all_points.extend (phantoms);
+ } break;
+#endif
+ default:
+ all_points.extend (phantoms);
+ break;
+ }
+
+ if (depth == 0 && shift_points_hori) /* 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_without_var_scaled (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_without_var_scaled (font, glyf_accelerator, gid, extents);
+ }
+
+ hb_bytes_t get_bytes () const { return bytes; }
+
+ Glyph () : bytes (),
+ header (bytes.as<GlyphHeader> ()),
+ gid (-1),
+ type(EMPTY)
+ {}
+
+ Glyph (hb_bytes_t bytes_,
+ hb_codepoint_t gid_ = (unsigned) -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 if (num_contours == -2) type = VAR_COMPOSITE;
+ 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/src/OT/glyf/GlyphHeader.hh b/src/OT/glyf/GlyphHeader.hh
new file mode 100644
index 000000000..e4a9168b7
--- /dev/null
+++ b/src/OT/glyf/GlyphHeader.hh
@@ -0,0 +1,50 @@
+#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_without_var_scaled (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); */
+ int lsb = hb_min (xMin, xMax);
+ (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+ extents->x_bearing = font->em_scale_x (lsb);
+ 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/src/OT/glyf/SimpleGlyph.hh b/src/OT/glyf/SimpleGlyph.hh
new file mode 100644
index 000000000..2b4aa99d2
--- /dev/null
+++ b/src/OT/glyf/SimpleGlyph.hh
@@ -0,0 +1,339 @@
+#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; i++)
+ 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);
+ }
+
+ static void encode_coord (int value,
+ uint8_t &flag,
+ const simple_glyph_flag_t short_flag,
+ const simple_glyph_flag_t same_flag,
+ hb_vector_t<uint8_t> &coords /* OUT */)
+ {
+ if (value == 0)
+ {
+ flag |= same_flag;
+ }
+ else if (value >= -255 && value <= 255)
+ {
+ flag |= short_flag;
+ if (value > 0) flag |= same_flag;
+ else value = -value;
+
+ coords.arrayZ[coords.length++] = (uint8_t) value;
+ }
+ else
+ {
+ int16_t val = value;
+ coords.arrayZ[coords.length++] = val >> 8;
+ coords.arrayZ[coords.length++] = val & 0xff;
+ }
+ }
+
+ static void encode_flag (uint8_t &flag,
+ uint8_t &repeat,
+ uint8_t lastflag,
+ hb_vector_t<uint8_t> &flags /* OUT */)
+ {
+ if (flag == lastflag && repeat != 255)
+ {
+ repeat++;
+ if (repeat == 1)
+ {
+ /* We know there's room. */
+ flags.arrayZ[flags.length++] = flag;
+ }
+ else
+ {
+ unsigned len = flags.length;
+ flags.arrayZ[len-2] = flag | FLAG_REPEAT;
+ flags.arrayZ[len-1] = repeat;
+ }
+ }
+ else
+ {
+ repeat = 0;
+ flags.push (flag);
+ }
+ }
+
+ bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
+ bool no_hinting,
+ hb_bytes_t &dest_bytes /* OUT */)
+ {
+ if (header.numberOfContours == 0 || all_points.length <= 4)
+ {
+ dest_bytes = hb_bytes_t ();
+ return true;
+ }
+ unsigned num_points = all_points.length - 4;
+
+ hb_vector_t<uint8_t> flags, x_coords, y_coords;
+ if (unlikely (!flags.alloc (num_points))) return false;
+ if (unlikely (!x_coords.alloc (2*num_points))) return false;
+ if (unlikely (!y_coords.alloc (2*num_points))) return false;
+
+ uint8_t lastflag = 255, repeat = 0;
+ int prev_x = 0, prev_y = 0;
+
+ for (unsigned i = 0; i < num_points; i++)
+ {
+ uint8_t flag = all_points.arrayZ[i].flag;
+ flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
+
+ int cur_x = roundf (all_points.arrayZ[i].x);
+ int cur_y = roundf (all_points.arrayZ[i].y);
+ encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
+ encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
+ encode_flag (flag, repeat, lastflag, flags);
+
+ prev_x = cur_x;
+ prev_y = cur_y;
+ lastflag = flag;
+ }
+
+ unsigned len_before_instrs = 2 * header.numberOfContours + 2;
+ unsigned len_instrs = instructions_length ();
+ unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
+
+ if (!no_hinting)
+ total_len += len_instrs;
+
+ char *p = (char *) hb_malloc (total_len);
+ if (unlikely (!p)) return false;
+
+ const char *src = bytes.arrayZ + GlyphHeader::static_size;
+ char *cur = p;
+ hb_memcpy (p, src, len_before_instrs);
+
+ cur += len_before_instrs;
+ src += len_before_instrs;
+
+ if (!no_hinting)
+ {
+ hb_memcpy (cur, src, len_instrs);
+ cur += len_instrs;
+ }
+
+ hb_memcpy (cur, flags.arrayZ, flags.length);
+ cur += flags.length;
+
+ hb_memcpy (cur, x_coords.arrayZ, x_coords.length);
+ cur += x_coords.length;
+
+ hb_memcpy (cur, y_coords.arrayZ, y_coords.length);
+
+ dest_bytes = hb_bytes_t (p, total_len);
+ return true;
+ }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_SIMPLEGLYPH_HH */
diff --git a/src/OT/glyf/SubsetGlyph.hh b/src/OT/glyf/SubsetGlyph.hh
new file mode 100644
index 000000000..1a0370c75
--- /dev/null
+++ b/src/OT/glyf/SubsetGlyph.hh
@@ -0,0 +1,93 @@
+#ifndef OT_GLYF_SUBSETGLYPH_HH
+#define OT_GLYF_SUBSETGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+
+struct glyf_accelerator_t;
+
+namespace glyf_impl {
+
+
+struct SubsetGlyph
+{
+ 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,
+ hb_font_t *font)
+ {
+ TRACE_SERIALIZE (this);
+
+ if (font)
+ {
+ const OT::glyf_accelerator_t &glyf = *font->face->table.glyf;
+ if (!this->compile_bytes_with_deltas (plan, font, glyf))
+ return_trace (false);
+ }
+
+ 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_gid(), &new_gid))
+ const_cast<CompositeGlyphRecord &> (_).set_gid (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);
+ }
+
+ bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+ hb_font_t *font,
+ const glyf_accelerator_t &glyf)
+ { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); }
+
+ void free_compiled_bytes ()
+ {
+ dest_start.fini ();
+ dest_end.fini ();
+ }
+
+ 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/src/OT/glyf/VarCompositeGlyph.hh b/src/OT/glyf/VarCompositeGlyph.hh
new file mode 100644
index 000000000..0f4c71c83
--- /dev/null
+++ b/src/OT/glyf/VarCompositeGlyph.hh
@@ -0,0 +1,353 @@
+#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
+#define OT_GLYF_VARCOMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+#include "coord-setter.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct VarCompositeGlyphRecord
+{
+ protected:
+ enum var_composite_glyph_flag_t
+ {
+ USE_MY_METRICS = 0x0001,
+ AXIS_INDICES_ARE_SHORT = 0x0002,
+ UNIFORM_SCALE = 0x0004,
+ HAVE_TRANSLATE_X = 0x0008,
+ HAVE_TRANSLATE_Y = 0x0010,
+ HAVE_ROTATION = 0x0020,
+ HAVE_SCALE_X = 0x0040,
+ HAVE_SCALE_Y = 0x0080,
+ HAVE_SKEW_X = 0x0100,
+ HAVE_SKEW_Y = 0x0200,
+ HAVE_TCENTER_X = 0x0400,
+ HAVE_TCENTER_Y = 0x0800,
+ GID_IS_24 = 0x1000,
+ AXES_HAVE_VARIATION = 0x2000,
+ };
+
+ public:
+
+ unsigned int get_size () const
+ {
+ unsigned int size = min_size;
+
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
+ size += numAxes * axis_width;
+
+ // gid
+ size += 2;
+ if (flags & GID_IS_24) size += 1;
+
+ if (flags & HAVE_TRANSLATE_X) size += 2;
+ if (flags & HAVE_TRANSLATE_Y) size += 2;
+ if (flags & HAVE_ROTATION) size += 2;
+ if (flags & HAVE_SCALE_X) size += 2;
+ if (flags & HAVE_SCALE_Y) size += 2;
+ if (flags & HAVE_SKEW_X) size += 2;
+ if (flags & HAVE_SKEW_Y) size += 2;
+ if (flags & HAVE_TCENTER_X) size += 2;
+ if (flags & HAVE_TCENTER_Y) size += 2;
+
+ return size;
+ }
+
+ bool has_more () const { return true; }
+
+ bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
+
+ hb_codepoint_t get_gid () const
+ {
+ if (flags & GID_IS_24)
+ return StructAfter<const HBGlyphID24> (numAxes);
+ else
+ return StructAfter<const HBGlyphID16> (numAxes);
+ }
+
+ unsigned get_numAxes () const
+ {
+ return numAxes;
+ }
+
+ unsigned get_num_points () const
+ {
+ unsigned num = 0;
+ if (flags & AXES_HAVE_VARIATION) num += numAxes;
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
+ if (flags & HAVE_ROTATION) num++;
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
+ return num;
+ }
+
+ void transform_points (hb_array_t<contour_point_t> record_points,
+ contour_point_vector_t &points) const
+ {
+ float matrix[4];
+ contour_point_t trans;
+
+ get_transformation_from_points (record_points, matrix, trans);
+
+ points.transform (matrix);
+ points.translate (trans);
+ }
+
+ static inline void transform (float (&matrix)[4], contour_point_t &trans,
+ float (other)[6])
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
+ float xx1 = other[0];
+ float xy1 = other[1];
+ float yx1 = other[2];
+ float yy1 = other[3];
+ float dx1 = other[4];
+ float dy1 = other[5];
+ float xx2 = matrix[0];
+ float xy2 = matrix[1];
+ float yx2 = matrix[2];
+ float yy2 = matrix[3];
+ float dx2 = trans.x;
+ float dy2 = trans.y;
+
+ matrix[0] = xx1*xx2 + xy1*yx2;
+ matrix[1] = xx1*xy2 + xy1*yy2;
+ matrix[2] = yx1*xx2 + yy1*yx2;
+ matrix[3] = yx1*xy2 + yy1*yy2;
+ trans.x = xx2*dx1 + yx2*dy1 + dx2;
+ trans.y = xy2*dx1 + yy2*dy1 + dy2;
+ }
+
+ static void translate (float (&matrix)[4], contour_point_t &trans,
+ float translateX, float translateY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
+ float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
+ transform (matrix, trans, other);
+ }
+
+ static void scale (float (&matrix)[4], contour_point_t &trans,
+ float scaleX, float scaleY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
+ float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ static void rotate (float (&matrix)[4], contour_point_t &trans,
+ float rotation)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
+ rotation = rotation * float (M_PI);
+ float c = cosf (rotation);
+ float s = sinf (rotation);
+ float other[6] = {c, s, -s, c, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ static void skew (float (&matrix)[4], contour_point_t &trans,
+ float skewX, float skewY)
+ {
+ // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
+ skewX = skewX * float (M_PI);
+ skewY = skewY * float (M_PI);
+ float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
+ transform (matrix, trans, other);
+ }
+
+ bool get_points (contour_point_vector_t &points) const
+ {
+ float translateX = 0.f;
+ float translateY = 0.f;
+ float rotation = 0.f;
+ float scaleX = 1.f * (1 << 12);
+ float scaleY = 1.f * (1 << 12);
+ float skewX = 0.f;
+ float skewY = 0.f;
+ float tCenterX = 0.f;
+ float tCenterY = 0.f;
+
+ if (unlikely (!points.resize (points.length + get_num_points ()))) return false;
+
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+ unsigned axes_size = numAxes * axis_width;
+
+ const F2DOT14 *q = (const F2DOT14 *) (axes_size +
+ (flags & GID_IS_24 ? 3 : 2) +
+ &StructAfter<const HBUINT8> (numAxes));
+
+ hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ());
+
+ unsigned count = numAxes;
+ if (flags & AXES_HAVE_VARIATION)
+ {
+ for (unsigned i = 0; i < count; i++)
+ rec_points[i].x = *q++;
+ rec_points += count;
+ }
+ else
+ q += count;
+
+ const HBUINT16 *p = (const HBUINT16 *) q;
+
+ if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
+ if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
+ if (flags & HAVE_ROTATION) rotation = * (const F2DOT14 *) p++;
+ if (flags & HAVE_SCALE_X) scaleX = * (const F4DOT12 *) p++;
+ if (flags & HAVE_SCALE_Y) scaleY = * (const F4DOT12 *) p++;
+ if (flags & HAVE_SKEW_X) skewX = * (const F2DOT14 *) p++;
+ if (flags & HAVE_SKEW_Y) skewY = * (const F2DOT14 *) p++;
+ if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
+ if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
+
+ if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
+ scaleY = scaleX;
+
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ {
+ rec_points[0].x = translateX;
+ rec_points[0].y = translateY;
+ rec_points++;
+ }
+ if (flags & HAVE_ROTATION)
+ {
+ rec_points[0].x = rotation;
+ rec_points++;
+ }
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ {
+ rec_points[0].x = scaleX;
+ rec_points[0].y = scaleY;
+ rec_points++;
+ }
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ {
+ rec_points[0].x = skewX;
+ rec_points[0].y = skewY;
+ rec_points++;
+ }
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ {
+ rec_points[0].x = tCenterX;
+ rec_points[0].y = tCenterY;
+ rec_points++;
+ }
+ assert (!rec_points);
+
+ return true;
+ }
+
+ void get_transformation_from_points (hb_array_t<contour_point_t> rec_points,
+ float (&matrix)[4], contour_point_t &trans) const
+ {
+ if (flags & AXES_HAVE_VARIATION)
+ rec_points += numAxes;
+
+ matrix[0] = matrix[3] = 1.f;
+ matrix[1] = matrix[2] = 0.f;
+ trans.init (0.f, 0.f);
+
+ float translateX = 0.f;
+ float translateY = 0.f;
+ float rotation = 0.f;
+ float scaleX = 1.f;
+ float scaleY = 1.f;
+ float skewX = 0.f;
+ float skewY = 0.f;
+ float tCenterX = 0.f;
+ float tCenterY = 0.f;
+
+ if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ {
+ translateX = rec_points[0].x;
+ translateY = rec_points[0].y;
+ rec_points++;
+ }
+ if (flags & HAVE_ROTATION)
+ {
+ rotation = rec_points[0].x / (1 << 14);
+ rec_points++;
+ }
+ if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ {
+ scaleX = rec_points[0].x / (1 << 12);
+ scaleY = rec_points[0].y / (1 << 12);
+ rec_points++;
+ }
+ if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ {
+ skewX = rec_points[0].x / (1 << 14);
+ skewY = rec_points[0].y / (1 << 14);
+ rec_points++;
+ }
+ if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ {
+ tCenterX = rec_points[0].x;
+ tCenterY = rec_points[0].y;
+ rec_points++;
+ }
+ assert (!rec_points);
+
+ translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
+ rotate (matrix, trans, rotation);
+ scale (matrix, trans, scaleX, scaleY);
+ skew (matrix, trans, -skewX, skewY);
+ translate (matrix, trans, -tCenterX, -tCenterY);
+ }
+
+ void set_variations (coord_setter_t &setter,
+ hb_array_t<contour_point_t> rec_points) const
+ {
+ bool have_variations = flags & AXES_HAVE_VARIATION;
+ unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+
+ const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
+ const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
+
+ const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
+
+ unsigned count = numAxes;
+ for (unsigned i = 0; i < count; i++)
+ {
+ unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
+
+ signed v = have_variations ? rec_points[i].x : *a++;
+
+ v += setter[axis_index];
+ v = hb_clamp (v, -(1<<14), (1<<14));
+ setter[axis_index] = v;
+ }
+ }
+
+ protected:
+ HBUINT16 flags;
+ HBUINT8 numAxes;
+ public:
+ DEFINE_SIZE_MIN (3);
+};
+
+using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
+
+struct VarCompositeGlyph
+{
+ const GlyphHeader &header;
+ hb_bytes_t bytes;
+ VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+ header (header_), bytes (bytes_) {}
+
+ var_composite_iter_t iter () const
+ { return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
+
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */
diff --git a/src/OT/glyf/composite-iter.hh b/src/OT/glyf/composite-iter.hh
new file mode 100644
index 000000000..d05701f3d
--- /dev/null
+++ b/src/OT/glyf/composite-iter.hh
@@ -0,0 +1,68 @@
+#ifndef OT_GLYF_COMPOSITE_ITER_HH
+#define OT_GLYF_COMPOSITE_ITER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+template <typename CompositeGlyphRecord>
+struct composite_iter_tmpl : hb_iter_with_fallback_t<composite_iter_tmpl<CompositeGlyphRecord>,
+ const CompositeGlyphRecord &>
+{
+ typedef const CompositeGlyphRecord *__item_t__;
+ composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) :
+ glyph (glyph_), current (nullptr), current_size (0)
+ {
+ set_current (current_);
+ }
+
+ composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
+
+ const CompositeGlyphRecord & __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_tmpl __end__ () const { return composite_iter_tmpl (); }
+ bool operator != (const composite_iter_tmpl& 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;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COMPOSITE_ITER_HH */
diff --git a/src/OT/glyf/coord-setter.hh b/src/OT/glyf/coord-setter.hh
new file mode 100644
index 000000000..df64ed5af
--- /dev/null
+++ b/src/OT/glyf/coord-setter.hh
@@ -0,0 +1,34 @@
+#ifndef OT_GLYF_COORD_SETTER_HH
+#define OT_GLYF_COORD_SETTER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct coord_setter_t
+{
+ coord_setter_t (hb_array_t<int> coords) :
+ coords (coords) {}
+
+ int& operator [] (unsigned idx)
+ {
+ if (coords.length < idx + 1)
+ coords.resize (idx + 1);
+ return coords[idx];
+ }
+
+ hb_array_t<int> get_coords ()
+ { return coords.as_array (); }
+
+ hb_vector_t<int> coords;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COORD_SETTER_HH */
diff --git a/src/OT/glyf/glyf-helpers.hh b/src/OT/glyf/glyf-helpers.hh
new file mode 100644
index 000000000..181c33d06
--- /dev/null
+++ b/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/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh
new file mode 100644
index 000000000..e6e985c38
--- /dev/null
+++ b/src/OT/glyf/glyf.hh
@@ -0,0 +1,448 @@
+#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,
+ hb_font_t *font)
+ {
+ TRACE_SERIALIZE (this);
+
+ unsigned init_len = c->length ();
+ for (auto &_ : it)
+ if (unlikely (!_.serialize (c, use_short_loca, plan, font)))
+ return false;
+
+ /* 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);
+
+ hb_font_t *font = nullptr;
+ if (!c->plan->pinned_at_default)
+ {
+ font = _create_font_for_instancing (c->plan);
+ if (unlikely (!font)) return false;
+ }
+
+ auto padded_offsets =
+ + hb_iter (glyphs)
+ | hb_map (&glyf_impl::SubsetGlyph::padded_size)
+ ;
+
+ bool use_short_loca = false;
+ if (likely (!c->plan->force_long_loca))
+ {
+ unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
+ use_short_loca = max_offset < 0x1FFFF;
+ }
+
+ glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font);
+ if (!use_short_loca) {
+ padded_offsets =
+ + hb_iter (glyphs)
+ | hb_map (&glyf_impl::SubsetGlyph::length)
+ ;
+ }
+
+ if (font)
+ {
+ _free_compiled_subset_glyphs (&glyphs);
+ hb_font_destroy (font);
+ }
+
+ 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;
+
+ hb_font_t *
+ _create_font_for_instancing (const hb_subset_plan_t *plan) const;
+
+ void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const
+ {
+ for (auto _ : *glyphs)
+ _.free_compiled_bytes ();
+ }
+
+ 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, nullptr, true, true, 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;
+ bool scaled;
+
+ 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, bool scaled)
+ {
+ if (unlikely (empty ()))
+ {
+ extents->width = 0;
+ extents->x_bearing = 0;
+ extents->height = 0;
+ extents->y_bearing = 0;
+ return;
+ }
+ if (scaled)
+ {
+ 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;
+ }
+ else
+ {
+ extents->x_bearing = roundf (min_x);
+ extents->width = roundf (max_x - extents->x_bearing);
+ extents->y_bearing = roundf (max_y);
+ extents->height = roundf (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_, bool scaled_)
+ {
+ font = font_;
+ extents = extents_;
+ phantoms = phantoms_;
+ scaled = scaled_;
+ 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, scaled); }
+
+ bool is_consuming_contour_points () { return extents; }
+ contour_point_t *get_phantoms_sink () { return phantoms; }
+ };
+
+ public:
+ unsigned
+ get_advance_with_var_unscaled (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 (font->num_coords)
+ success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
+
+ if (unlikely (!success))
+ return
+#ifndef HB_NO_VERTICAL
+ is_vertical ? vmtx->get_advance_without_var_unscaled (gid) :
+#endif
+ hmtx->get_advance_without_var_unscaled (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);
+ }
+
+ bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const
+ {
+ if (unlikely (gid >= num_glyphs)) return false;
+
+ 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, false))))
+ return false;
+
+ *lsb = is_vertical
+ ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
+ : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+ return true;
+ }
+#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, true));
+#endif
+ return glyph_for_gid (gid).get_extents_without_var_scaled (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);
+ unsigned num_glyphs = plan->num_output_glyphs ();
+ if (!glyphs.resize (num_glyphs)) return;
+
+ for (auto p : plan->glyph_map->iter ())
+ {
+ unsigned new_gid = p.second;
+ glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
+ subset_glyph.old_gid = p.first;
+
+ if (unlikely (new_gid == 0 &&
+ !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
+ plan->pinned_at_default)
+ subset_glyph.source_glyph = glyf_impl::Glyph ();
+ else
+ {
+ /* If plan has an accelerator, the preprocessing step already trimmed glyphs.
+ * Don't trim them again! */
+ subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator);
+ }
+
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ subset_glyph.drop_hints_bytes ();
+ else
+ subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+ }
+}
+
+inline hb_font_t *
+glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
+{
+ hb_font_t *font = hb_font_create (plan->source);
+ if (unlikely (font == hb_font_get_empty ())) return nullptr;
+
+ hb_vector_t<hb_variation_t> vars;
+ if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
+ return nullptr;
+
+ for (auto _ : *plan->user_axes_location)
+ {
+ hb_variation_t var;
+ var.tag = _.first;
+ var.value = _.second;
+ vars.push (var);
+ }
+
+#ifndef HB_NO_VAR
+ hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+#endif
+ return font;
+}
+
+
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYF_HH */
diff --git a/src/OT/glyf/loca.hh b/src/OT/glyf/loca.hh
new file mode 100644
index 000000000..4481cba8e
--- /dev/null
+++ b/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/src/OT/glyf/path-builder.hh b/src/OT/glyf/path-builder.hh
new file mode 100644
index 000000000..9bfc45a1a
--- /dev/null
+++ b/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/src/check-c-linkage-decls.py b/src/check-c-linkage-decls.py
index b7532a7e9..fe18eda89 100755
--- a/src/check-c-linkage-decls.py
+++ b/src/check-c-linkage-decls.py
@@ -2,13 +2,23 @@
import sys, os
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+ abs_path = os.path.join(base_srcdir, s)
+ return os.path.relpath(abs_path, srcdir)
+
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
- [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
-
+HBSOURCES = [
+ removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+ x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
stat = 0
for x in HBHEADERS:
diff --git a/src/check-header-guards.py b/src/check-header-guards.py
index 0ad42cd84..35ae6bef6 100755
--- a/src/check-header-guards.py
+++ b/src/check-header-guards.py
@@ -2,21 +2,33 @@
import sys, os, re
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+ abs_path = os.path.join(base_srcdir, s)
+ return os.path.relpath(abs_path, srcdir)
+
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
- [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
+HBSOURCES = [
+ removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+ x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
stat = 0
for x in HBHEADERS + HBSOURCES:
if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
- tag = x.upper ().replace ('.', '_').replace ('-', '_')
+ tag = x.upper ().replace ('.', '_').replace ('-', '_').replace(os.path.sep, '_').replace('/', '_')
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
if len (re.findall (tag + r'\b', content)) != 3:
- print ('Ouch, header file %s does not have correct preprocessor guards' % x)
+ print ('Ouch, header file %s does not have correct preprocessor guards. Expected: %s' % (x, tag))
stat = 1
sys.exit (stat)
diff --git a/src/check-includes.py b/src/check-includes.py
index 88eaa2eaa..fc95874b1 100755
--- a/src/check-includes.py
+++ b/src/check-includes.py
@@ -2,12 +2,24 @@
import sys, os, re
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+ abs_path = os.path.join(base_srcdir, s)
+ return os.path.relpath(abs_path, srcdir)
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
- [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
+
+HBSOURCES = [
+ removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+ x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
stat = 0
@@ -25,7 +37,7 @@ for x in HBSOURCES:
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
includes = re.findall (r'#.*include.*', content)
if includes:
- if not len (re.findall (r'"hb.*\.hh"', includes[0])):
+ if not len (re.findall (r'".*\.hh"', includes[0])):
print ('failure on %s' % x)
stat = 1
diff --git a/src/check-static-inits.py b/src/check-static-inits.py
index 37e0590fa..c6e2db1ea 100755
--- a/src/check-static-inits.py
+++ b/src/check-static-inits.py
@@ -14,7 +14,7 @@ if sys.version_info < (3, 5):
print ('check-static-inits.py: needs python 3.5 for recursive support in glob')
sys.exit (77)
-OBJS = glob.glob (os.path.join (builddir, libs, '**', '*.o'), recursive=True)
+OBJS = glob.glob (os.path.join (builddir, libs, '**', '*hb*.o'), recursive=True)
if not OBJS:
print ('check-static-inits.py: object files not found; skipping test')
sys.exit (77)
diff --git a/src/check-symbols.py b/src/check-symbols.py
index 385959bde..d0b8bd3c8 100755
--- a/src/check-symbols.py
+++ b/src/check-symbols.py
@@ -17,7 +17,7 @@ if not nm:
print ('check-symbols.py: \'nm\' not found; skipping test')
sys.exit (77)
-cxxflit = shutil.which ('c++filt')
+cxxfilt = shutil.which ('c++filt')
tested = False
stat = 0
@@ -31,13 +31,13 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
symprefix = '_' if suffix == 'dylib' else ''
EXPORTED_SYMBOLS = [s.split ()[2]
- for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
+ for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
- # run again c++flit also if is available
- if cxxflit:
+ # run again c++filt also if is available
+ if cxxfilt:
EXPORTED_SYMBOLS = subprocess.check_output (
- [cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode ()
+ [cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
).decode ('utf-8').splitlines ()
prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
diff --git a/src/failing-alloc.c b/src/failing-alloc.c
index 1bf18cd67..1bfb935b9 100644
--- a/src/failing-alloc.c
+++ b/src/failing-alloc.c
@@ -25,6 +25,10 @@
#include <stdlib.h>
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int alloc_state = 0;
__attribute__((no_sanitize("integer")))
@@ -55,3 +59,7 @@ void hb_free_impl (void *ptr)
{
return free (ptr);
}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/fix_get_types.py b/src/fix_get_types.py
index 208b9dfcd..208b9dfcd 100644..100755
--- a/src/fix_get_types.py
+++ b/src/fix_get_types.py
diff --git a/src/gen-arabic-joining-list.py b/src/gen-arabic-joining-list.py
index 8162a4a3e..7ec7425fd 100755
--- a/src/gen-arabic-joining-list.py
+++ b/src/gen-arabic-joining-list.py
@@ -94,13 +94,13 @@ for h in headers:
print (" * %s" % (l.strip ()))
print (" */")
print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
+print ("#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
+print ("#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
print ()
print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */")
+print ("#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */")
print ()
print ("/* == End of generated function == */")
diff --git a/src/gen-arabic-pua.py b/src/gen-arabic-pua.py
new file mode 100755
index 000000000..4cf290087
--- /dev/null
+++ b/src/gen-arabic-pua.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+
+"""usage: ./gen-arabic-pua.py
+"""
+
+import packTab
+
+
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" * ./gen-arabic-pua.py")
+print (" *")
+print (" */")
+print ()
+print ("#ifndef HB_OT_SHAPER_ARABIC_PUA_HH")
+print ("#define HB_OT_SHAPER_ARABIC_PUA_HH")
+print ()
+
+code = packTab.Code('_hb_arabic')
+
+for p in ("ArabicPUASimplified.txt", "ArabicPUATraditional.txt"):
+ with open (p, encoding='utf-8') as f:
+ fields = [l.split('\t') for l in f if l[:1] != '#']
+ data = {int(fs[1], 16):int(fs[0], 16) for fs in fields}
+ sol = packTab.pack_table(data, compression=9)
+ sol.genCode(code, f'pua_{p[9:13].lower()}_map')
+
+code.print_c(linkage='static inline')
+
+print ()
+print ("#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */")
+print ()
+print ("/* == End of generated table == */")
diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py
index 621d5b60c..8278d7d69 100755
--- a/src/gen-arabic-table.py
+++ b/src/gen-arabic-table.py
@@ -153,12 +153,29 @@ def print_joining_table(f):
print ("#undef %s" % (short))
print ()
+LIGATURES = (
+ 0xF2EE, 0xFC08, 0xFC0E, 0xFC12, 0xFC32, 0xFC3F, 0xFC40, 0xFC41, 0xFC42,
+ 0xFC44, 0xFC4E, 0xFC5E, 0xFC60, 0xFC61, 0xFC62, 0xFC6A, 0xFC6D, 0xFC6F,
+ 0xFC70, 0xFC73, 0xFC75, 0xFC86, 0xFC8F, 0xFC91, 0xFC94, 0xFC9C, 0xFC9D,
+ 0xFC9E, 0xFC9F, 0xFCA1, 0xFCA2, 0xFCA3, 0xFCA4, 0xFCA8, 0xFCAA, 0xFCAC,
+ 0xFCB0, 0xFCC9, 0xFCCA, 0xFCCB, 0xFCCC, 0xFCCD, 0xFCCE, 0xFCCF, 0xFCD0,
+ 0xFCD1, 0xFCD2, 0xFCD3, 0xFCD5, 0xFCDA, 0xFCDB, 0xFCDC, 0xFCDD, 0xFD30,
+ 0xFD88, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC,
+ 0xF201, 0xF211, 0xF2EE,
+)
+
def print_shaping_table(f):
shapes = {}
ligatures = {}
names = {}
- for line in f:
+ lines = f.readlines()
+ lines += [
+ "F201;PUA ARABIC LIGATURE LELLAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 0644 0647;;;;N;;;;;",
+ "F211;PUA ARABIC LIGATURE LAM WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062C;;;;N;;;;;",
+ "F2EE;PUA ARABIC LIGATURE SHADDA WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B 0651;;;;N;;;;;",
+ ]
+ for line in lines:
fields = [x.strip () for x in line.split (';')]
if fields[5][0:1] != '<':
@@ -166,14 +183,19 @@ def print_shaping_table(f):
items = fields[5].split (' ')
shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:])
+ c = int (fields[0], 16)
if not shape in ['initial', 'medial', 'isolated', 'final']:
continue
- c = int (fields[0], 16)
if len (items) != 1:
- # We only care about lam-alef ligatures
- if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]:
+ # Mark ligatures start with space and are in visual order, so we
+ # remove the space and reverse the items.
+ if items[0] == 0x0020:
+ items = items[:0:-1]
+ shape = None
+ # We only care about a subset of ligatures
+ if c not in LIGATURES:
continue
# Save ligature
@@ -209,34 +231,99 @@ def print_shaping_table(f):
print ("#define SHAPING_TABLE_LAST 0x%04Xu" % max_u)
print ()
- ligas = {}
- for pair in ligatures.keys ():
- for shape in ligatures[pair]:
- c = ligatures[pair][shape]
- if shape == 'isolated':
- liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final'])
- elif shape == 'final':
- liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final'])
+ ligas_2 = {}
+ ligas_3 = {}
+ ligas_mark_2 = {}
+ for key in ligatures.keys ():
+ for shape in ligatures[key]:
+ c = ligatures[key][shape]
+ if len(key) == 3:
+ if shape == 'isolated':
+ liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'], shapes[key[2]]['final'])
+ elif shape == 'final':
+ liga = (shapes[key[0]]['medial'], shapes[key[1]]['medial'], shapes[key[2]]['final'])
+ elif shape == 'initial':
+ liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'], shapes[key[2]]['medial'])
+ else:
+ raise Exception ("Unexpected shape", shape)
+ if liga[0] not in ligas_3:
+ ligas_3[liga[0]] = []
+ ligas_3[liga[0]].append ((liga[1], liga[2], c))
+ elif len(key) == 2:
+ if shape is None:
+ liga = key
+ if liga[0] not in ligas_mark_2:
+ ligas_mark_2[liga[0]] = []
+ ligas_mark_2[liga[0]].append ((liga[1], c))
+ continue
+ elif shape == 'isolated':
+ liga = (shapes[key[0]]['initial'], shapes[key[1]]['final'])
+ elif shape == 'final':
+ liga = (shapes[key[0]]['medial'], shapes[key[1]]['final'])
+ elif shape == 'initial':
+ liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'])
+ else:
+ raise Exception ("Unexpected shape", shape)
+ if liga[0] not in ligas_2:
+ ligas_2[liga[0]] = []
+ ligas_2[liga[0]].append ((liga[1], c))
else:
- raise Exception ("Unexpected shape", shape)
- if liga[0] not in ligas:
- ligas[liga[0]] = []
- ligas[liga[0]].append ((liga[1], c))
- max_i = max (len (ligas[l]) for l in ligas)
+ raise Exception ("Unexpected number of ligature components", key)
+ max_i = max (len (ligas_2[l]) for l in ligas_2)
print ()
print ("static const struct ligature_set_t {")
print (" uint16_t first;")
print (" struct ligature_pairs_t {")
- print (" uint16_t second;")
+ print (" uint16_t components[1];")
print (" uint16_t ligature;")
print (" } ligatures[%d];" % max_i)
print ("} ligature_table[] =")
print ("{")
- for first in sorted (ligas.keys ()):
+ for first in sorted (ligas_2.keys ()):
+
+ print (" { 0x%04Xu, {" % (first))
+ for liga in ligas_2[first]:
+ print (" { {0x%04Xu}, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+ print (" }},")
+
+ print ("};")
+ print ()
+
+ max_i = max (len (ligas_mark_2[l]) for l in ligas_mark_2)
+ print ()
+ print ("static const struct ligature_mark_set_t {")
+ print (" uint16_t first;")
+ print (" struct ligature_pairs_t {")
+ print (" uint16_t components[1];")
+ print (" uint16_t ligature;")
+ print (" } ligatures[%d];" % max_i)
+ print ("} ligature_mark_table[] =")
+ print ("{")
+ for first in sorted (ligas_mark_2.keys ()):
+
+ print (" { 0x%04Xu, {" % (first))
+ for liga in ligas_mark_2[first]:
+ print (" { {0x%04Xu}, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+ print (" }},")
+
+ print ("};")
+ print ()
+
+ max_i = max (len (ligas_3[l]) for l in ligas_3)
+ print ()
+ print ("static const struct ligature_3_set_t {")
+ print (" uint16_t first;")
+ print (" struct ligature_triplets_t {")
+ print (" uint16_t components[2];")
+ print (" uint16_t ligature;")
+ print (" } ligatures[%d];" % max_i)
+ print ("} ligature_3_table[] =")
+ print ("{")
+ for first in sorted (ligas_3.keys ()):
print (" { 0x%04Xu, {" % (first))
- for liga in ligas[first]:
- print (" { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+ for liga in ligas_3[first]:
+ print (" { {0x%04Xu, 0x%04Xu}, 0x%04Xu}, /* %s */" % (liga[0], liga[1], liga[2], names[liga[2]]))
print (" }},")
print ("};")
@@ -257,8 +344,8 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
+print ("#ifndef HB_OT_SHAPER_ARABIC_TABLE_HH")
+print ("#define HB_OT_SHAPER_ARABIC_TABLE_HH")
print ()
read_blocks (files[2])
@@ -266,6 +353,6 @@ print_joining_table (files[0])
print_shaping_table (files[1])
print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */")
+print ("#endif /* HB_OT_SHAPER_ARABIC_TABLE_HH */")
print ()
print ("/* == End of generated table == */")
diff --git a/src/gen-def.py b/src/gen-def.py
index 33aa4df76..9b4efd4f3 100755
--- a/src/gen-def.py
+++ b/src/gen-def.py
@@ -19,24 +19,9 @@ symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re
if '--experimental-api' not in sys.argv:
# Move these to harfbuzz-sections.txt when got stable
experimental_symbols = \
-"""hb_font_draw_glyph
-hb_draw_funcs_t
-hb_draw_close_path_func_t
-hb_draw_cubic_to_func_t
-hb_draw_line_to_func_t
-hb_draw_move_to_func_t
-hb_draw_quadratic_to_func_t
-hb_draw_funcs_create
-hb_draw_funcs_destroy
-hb_draw_funcs_is_immutable
-hb_draw_funcs_make_immutable
-hb_draw_funcs_reference
-hb_draw_funcs_set_close_path_func
-hb_draw_funcs_set_cubic_to_func
-hb_draw_funcs_set_line_to_func
-hb_draw_funcs_set_move_to_func
-hb_draw_funcs_set_quadratic_to_func
-hb_font_get_var_coords_design""".splitlines ()
+"""hb_subset_repack_or_fail
+hb_subset_input_override_name_table
+""".splitlines ()
symbols = [x for x in symbols if x not in experimental_symbols]
symbols = "\n".join (symbols)
diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py
index 0ee8fecfa..42a3fb8de 100755
--- a/src/gen-emoji-table.py
+++ b/src/gen-emoji-table.py
@@ -65,7 +65,7 @@ for typ, s in ranges.items():
for i in range(start, end + 1):
arr[i] = 1
- sol = packTab.pack_table(arr, 0, compression=3)
+ sol = packTab.pack_table(arr, 0, compression=9)
code = packTab.Code('_hb_emoji')
sol.genCode(code, 'is_'+typ)
code.print_c(linkage='static inline')
@@ -91,8 +91,8 @@ with open(sys.argv[2]) as f:
continue
sequences.append(line)
-with open("../test/shaping/data/in-house/tests/emoji-clusters.tests", "w") as f:
+with open("../test/shape/data/in-house/tests/emoji-clusters.tests", "w") as f:
for sequence in sequences:
- f.write("../fonts/AdobeBlank2.ttf:--no-glyph-names --no-positions --font-funcs=ot")
- f.write(":" + ",".join(sequence))
- f.write(":[" + "|".join("1=0" for c in sequence) + "]\n")
+ f.write("../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot")
+ f.write(";" + ",".join(sequence))
+ f.write(";[" + "|".join("1=0" for c in sequence) + "]\n")
diff --git a/src/gen-harfbuzzcc.py b/src/gen-harfbuzzcc.py
index b25bcc7ab..227384043 100755
--- a/src/gen-harfbuzzcc.py
+++ b/src/gen-harfbuzzcc.py
@@ -9,10 +9,16 @@ if len (sys.argv) < 3:
OUTPUT = sys.argv[1]
CURRENT_SOURCE_DIR = sys.argv[2]
-sources = sys.argv[3:]
+
+# make sure input files are unique
+sources = sorted(set(sys.argv[3:]))
with open (OUTPUT, "wb") as f:
- f.write ("".join ('#include "{}"\n'.format (os.path.basename (x)) for x in sources if x.endswith (".cc")).encode ())
+ f.write ("".join ('#include "{}"\n'.format (os.path.relpath (os.path.abspath (x), CURRENT_SOURCE_DIR)) for x in sources if x.endswith (".cc")).encode ())
-# copy it also to src/
-shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+ with open(OUTPUT, "rb") as generated:
+ if baseline.read() != generated.read():
+ shutil.copyfile (OUTPUT, baseline_filename)
diff --git a/src/gen-hb-version.py b/src/gen-hb-version.py
index 4fac0a0e5..06018edfc 100755
--- a/src/gen-hb-version.py
+++ b/src/gen-hb-version.py
@@ -32,5 +32,9 @@ with open (INPUT, "r", encoding='utf-8') as template:
.replace ("@HB_VERSION@", version)
.encode ())
-# copy it also to src/
-shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+ with open(OUTPUT, "rb") as generated:
+ if baseline.read() != generated.read():
+ shutil.copyfile (OUTPUT, baseline_filename)
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index 367e55e27..4ef970265 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -26,7 +26,6 @@ ALLOWED_BLOCKS = [
'Telugu',
'Kannada',
'Malayalam',
- 'Sinhala',
'Myanmar',
'Khmer',
'Vedic Extensions',
@@ -41,8 +40,7 @@ files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
headers = [[f.readline () for i in range (2)] for f in files]
-data = [{} for _ in files]
-values = [{} for _ in files]
+unicode_data = [{} for _ in files]
for i, f in enumerate (files):
for line in f:
@@ -64,15 +62,12 @@ for i, f in enumerate (files):
t = fields[1]
for u in range (start, end + 1):
- data[i][u] = t
- values[i][t] = values[i].get (t, 0) + end - start + 1
+ unicode_data[i][u] = t
# Merge data into one dict:
defaults = ('Other', 'Not_Applicable', 'No_Block')
-for i,v in enumerate (defaults):
- values[i][v] = values[i].get (v, 0) + 1
combined = {}
-for i,d in enumerate (data):
+for i,d in enumerate (unicode_data):
for u,v in d.items ():
if i == 2 and not u in combined:
continue
@@ -80,14 +75,415 @@ for i,d in enumerate (data):
combined[u] = list (defaults)
combined[u][i] = v
combined = {k:v for k,v in combined.items() if k in ALLOWED_SINGLES or v[2] in ALLOWED_BLOCKS}
-data = combined
-del combined
+
+
+# Convert categories & positions types
+
+categories = {
+ 'indic' : [
+ 'X',
+ 'C',
+ 'V',
+ 'N',
+ 'H',
+ 'ZWNJ',
+ 'ZWJ',
+ 'M',
+ 'SM',
+ 'A',
+ 'VD',
+ 'PLACEHOLDER',
+ 'DOTTEDCIRCLE',
+ 'RS',
+ 'MPst',
+ 'Repha',
+ 'Ra',
+ 'CM',
+ 'Symbol',
+ 'CS',
+ ],
+ 'khmer' : [
+ 'VAbv',
+ 'VBlw',
+ 'VPre',
+ 'VPst',
+
+ 'Robatic',
+ 'Xgroup',
+ 'Ygroup',
+ ],
+ 'myanmar' : [
+ 'VAbv',
+ 'VBlw',
+ 'VPre',
+ 'VPst',
+
+ 'IV',
+ 'As',
+ 'DB',
+ 'GB',
+ 'MH',
+ 'MR',
+ 'MW',
+ 'MY',
+ 'PT',
+ 'VS',
+ 'ML',
+ ],
+}
+
+category_map = {
+ 'Other' : 'X',
+ 'Avagraha' : 'Symbol',
+ 'Bindu' : 'SM',
+ 'Brahmi_Joining_Number' : 'PLACEHOLDER', # Don't care.
+ 'Cantillation_Mark' : 'A',
+ 'Consonant' : 'C',
+ 'Consonant_Dead' : 'C',
+ 'Consonant_Final' : 'CM',
+ 'Consonant_Head_Letter' : 'C',
+ 'Consonant_Initial_Postfixed' : 'C', # TODO
+ 'Consonant_Killer' : 'M', # U+17CD only.
+ 'Consonant_Medial' : 'CM',
+ 'Consonant_Placeholder' : 'PLACEHOLDER',
+ 'Consonant_Preceding_Repha' : 'Repha',
+ 'Consonant_Prefixed' : 'X', # Don't care.
+ 'Consonant_Subjoined' : 'CM',
+ 'Consonant_Succeeding_Repha' : 'CM',
+ 'Consonant_With_Stacker' : 'CS',
+ 'Gemination_Mark' : 'SM', # https://github.com/harfbuzz/harfbuzz/issues/552
+ 'Invisible_Stacker' : 'H',
+ 'Joiner' : 'ZWJ',
+ 'Modifying_Letter' : 'X',
+ 'Non_Joiner' : 'ZWNJ',
+ 'Nukta' : 'N',
+ 'Number' : 'PLACEHOLDER',
+ 'Number_Joiner' : 'PLACEHOLDER', # Don't care.
+ 'Pure_Killer' : 'M', # Is like a vowel matra.
+ 'Register_Shifter' : 'RS',
+ 'Syllable_Modifier' : 'SM',
+ 'Tone_Letter' : 'X',
+ 'Tone_Mark' : 'N',
+ 'Virama' : 'H',
+ 'Visarga' : 'SM',
+ 'Vowel' : 'V',
+ 'Vowel_Dependent' : 'M',
+ 'Vowel_Independent' : 'V',
+}
+position_map = {
+ 'Not_Applicable' : 'END',
+
+ 'Left' : 'PRE_C',
+ 'Top' : 'ABOVE_C',
+ 'Bottom' : 'BELOW_C',
+ 'Right' : 'POST_C',
+
+ # These should resolve to the position of the last part of the split sequence.
+ 'Bottom_And_Right' : 'POST_C',
+ 'Left_And_Right' : 'POST_C',
+ 'Top_And_Bottom' : 'BELOW_C',
+ 'Top_And_Bottom_And_Left' : 'BELOW_C',
+ 'Top_And_Bottom_And_Right' : 'POST_C',
+ 'Top_And_Left' : 'ABOVE_C',
+ 'Top_And_Left_And_Right' : 'POST_C',
+ 'Top_And_Right' : 'POST_C',
+
+ 'Overstruck' : 'AFTER_MAIN',
+ 'Visual_order_left' : 'PRE_M',
+}
+
+category_overrides = {
+
+ # These are the variation-selectors. They only appear in the Myanmar grammar
+ # but are not Myanmar-specific
+ 0xFE00: 'VS',
+ 0xFE01: 'VS',
+ 0xFE02: 'VS',
+ 0xFE03: 'VS',
+ 0xFE04: 'VS',
+ 0xFE05: 'VS',
+ 0xFE06: 'VS',
+ 0xFE07: 'VS',
+ 0xFE08: 'VS',
+ 0xFE09: 'VS',
+ 0xFE0A: 'VS',
+ 0xFE0B: 'VS',
+ 0xFE0C: 'VS',
+ 0xFE0D: 'VS',
+ 0xFE0E: 'VS',
+ 0xFE0F: 'VS',
+
+ # These appear in the OT Myanmar spec, but are not Myanmar-specific
+ 0x2015: 'PLACEHOLDER',
+ 0x2022: 'PLACEHOLDER',
+ 0x25FB: 'PLACEHOLDER',
+ 0x25FC: 'PLACEHOLDER',
+ 0x25FD: 'PLACEHOLDER',
+ 0x25FE: 'PLACEHOLDER',
+
+
+ # Indic
+
+ 0x0930: 'Ra', # Devanagari
+ 0x09B0: 'Ra', # Bengali
+ 0x09F0: 'Ra', # Bengali
+ 0x0A30: 'Ra', # Gurmukhi No Reph
+ 0x0AB0: 'Ra', # Gujarati
+ 0x0B30: 'Ra', # Oriya
+ 0x0BB0: 'Ra', # Tamil No Reph
+ 0x0C30: 'Ra', # Telugu Reph formed only with ZWJ
+ 0x0CB0: 'Ra', # Kannada
+ 0x0D30: 'Ra', # Malayalam No Reph, Logical Repha
+
+ # The following act more like the Bindus.
+ 0x0953: 'SM',
+ 0x0954: 'SM',
+
+ # U+0A40 GURMUKHI VOWEL SIGN II may be preceded by U+0A02 GURMUKHI SIGN BINDI.
+ 0x0A40: 'MPst',
+
+ # The following act like consonants.
+ 0x0A72: 'C',
+ 0x0A73: 'C',
+ 0x1CF5: 'C',
+ 0x1CF6: 'C',
+
+ # TODO: The following should only be allowed after a Visarga.
+ # For now, just treat them like regular tone marks.
+ 0x1CE2: 'A',
+ 0x1CE3: 'A',
+ 0x1CE4: 'A',
+ 0x1CE5: 'A',
+ 0x1CE6: 'A',
+ 0x1CE7: 'A',
+ 0x1CE8: '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.
+ 0x1CED: 'A',
+
+ # The following take marks in standalone clusters, similar to Avagraha.
+ 0xA8F2: 'Symbol',
+ 0xA8F3: 'Symbol',
+ 0xA8F4: 'Symbol',
+ 0xA8F5: 'Symbol',
+ 0xA8F6: 'Symbol',
+ 0xA8F7: 'Symbol',
+ 0x1CE9: 'Symbol',
+ 0x1CEA: 'Symbol',
+ 0x1CEB: 'Symbol',
+ 0x1CEC: 'Symbol',
+ 0x1CEE: 'Symbol',
+ 0x1CEF: 'Symbol',
+ 0x1CF0: 'Symbol',
+ 0x1CF1: 'Symbol',
+
+ 0x0A51: 'M', # https://github.com/harfbuzz/harfbuzz/issues/524
+
+ # According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
+ # so the Indic shaper needs to know their categories.
+ 0x11301: 'SM',
+ 0x11302: 'SM',
+ 0x11303: 'SM',
+ 0x1133B: 'N',
+ 0x1133C: 'N',
+
+ 0x0AFB: 'N', # https://github.com/harfbuzz/harfbuzz/issues/552
+ 0x0B55: 'N', # https://github.com/harfbuzz/harfbuzz/issues/2849
+
+ 0x09FC: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/1613
+ 0x0C80: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/623
+ 0x0D04: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/3511
+
+ 0x25CC: 'DOTTEDCIRCLE',
+
+
+ # Khmer
+
+ 0x179A: 'Ra',
+
+ 0x17CC: 'Robatic',
+ 0x17C9: 'Robatic',
+ 0x17CA: 'Robatic',
+
+ 0x17C6: 'Xgroup',
+ 0x17CB: 'Xgroup',
+ 0x17CD: 'Xgroup',
+ 0x17CE: 'Xgroup',
+ 0x17CF: 'Xgroup',
+ 0x17D0: 'Xgroup',
+ 0x17D1: 'Xgroup',
+
+ 0x17C7: 'Ygroup',
+ 0x17C8: 'Ygroup',
+ 0x17DD: 'Ygroup',
+ 0x17D3: 'Ygroup', # Just guessing. Uniscribe doesn't categorize it.
+
+ 0x17D9: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/issues/2384
+
+
+ # Myanmar
+
+ # https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze
+
+ 0x104E: 'C', # The spec says C, IndicSyllableCategory says Consonant_Placeholder
+
+ 0x1004: 'Ra',
+ 0x101B: 'Ra',
+ 0x105A: 'Ra',
+
+ 0x1032: 'A',
+ 0x1036: 'A',
+
+ 0x103A: 'As',
+
+ #0x1040: 'D0', # XXX The spec says D0, but Uniscribe doesn't seem to do.
+
+ 0x103E: 'MH',
+ 0x1060: 'ML',
+ 0x103C: 'MR',
+ 0x103D: 'MW',
+ 0x1082: 'MW',
+ 0x103B: 'MY',
+ 0x105E: 'MY',
+ 0x105F: 'MY',
+
+ 0x1063: 'PT',
+ 0x1064: 'PT',
+ 0x1069: 'PT',
+ 0x106A: 'PT',
+ 0x106B: 'PT',
+ 0x106C: 'PT',
+ 0x106D: 'PT',
+ 0xAA7B: 'PT',
+
+ 0x1038: 'SM',
+ 0x1087: 'SM',
+ 0x1088: 'SM',
+ 0x1089: 'SM',
+ 0x108A: 'SM',
+ 0x108B: 'SM',
+ 0x108C: 'SM',
+ 0x108D: 'SM',
+ 0x108F: 'SM',
+ 0x109A: 'SM',
+ 0x109B: 'SM',
+ 0x109C: 'SM',
+
+ 0x104A: 'PLACEHOLDER',
+}
+position_overrides = {
+
+ 0x0A51: 'BELOW_C', # https://github.com/harfbuzz/harfbuzz/issues/524
+
+ 0x0B01: 'BEFORE_SUB', # Oriya Bindu is BeforeSub in the spec.
+}
+
+def matra_pos_left(u, block):
+ return "PRE_M"
+def matra_pos_right(u, block):
+ if block == 'Devanagari': return 'AFTER_SUB'
+ if block == 'Bengali': return 'AFTER_POST'
+ if block == 'Gurmukhi': return 'AFTER_POST'
+ if block == 'Gujarati': return 'AFTER_POST'
+ if block == 'Oriya': return 'AFTER_POST'
+ if block == 'Tamil': return 'AFTER_POST'
+ if block == 'Telugu': return 'BEFORE_SUB' if u <= 0x0C42 else 'AFTER_SUB'
+ if block == 'Kannada': return 'BEFORE_SUB' if u < 0x0CC3 or u > 0x0CD6 else 'AFTER_SUB'
+ if block == 'Malayalam': return 'AFTER_POST'
+ return 'AFTER_SUB'
+def matra_pos_top(u, block):
+ # BENG and MLYM don't have top matras.
+ if block == 'Devanagari': return 'AFTER_SUB'
+ if block == 'Gurmukhi': return 'AFTER_POST' # Deviate from spec
+ if block == 'Gujarati': return 'AFTER_SUB'
+ if block == 'Oriya': return 'AFTER_MAIN'
+ if block == 'Tamil': return 'AFTER_SUB'
+ if block == 'Telugu': return 'BEFORE_SUB'
+ if block == 'Kannada': return 'BEFORE_SUB'
+ return 'AFTER_SUB'
+def matra_pos_bottom(u, block):
+ if block == 'Devanagari': return 'AFTER_SUB'
+ if block == 'Bengali': return 'AFTER_SUB'
+ if block == 'Gurmukhi': return 'AFTER_POST'
+ if block == 'Gujarati': return 'AFTER_POST'
+ if block == 'Oriya': return 'AFTER_SUB'
+ if block == 'Tamil': return 'AFTER_POST'
+ if block == 'Telugu': return 'BEFORE_SUB'
+ if block == 'Kannada': return 'BEFORE_SUB'
+ if block == 'Malayalam': return 'AFTER_POST'
+ return "AFTER_SUB"
+def indic_matra_position(u, pos, block): # Reposition matra
+ if pos == 'PRE_C': return matra_pos_left(u, block)
+ if pos == 'POST_C': return matra_pos_right(u, block)
+ if pos == 'ABOVE_C': return matra_pos_top(u, block)
+ if pos == 'BELOW_C': return matra_pos_bottom(u, block)
+ assert (False)
+
+def position_to_category(pos):
+ if pos == 'PRE_C': return 'VPre'
+ if pos == 'ABOVE_C': return 'VAbv'
+ if pos == 'BELOW_C': return 'VBlw'
+ if pos == 'POST_C': return 'VPst'
+ assert(False)
+
+
+defaults = (category_map[defaults[0]], position_map[defaults[1]], defaults[2])
+
+indic_data = {}
+for k, (cat, pos, block) in combined.items():
+ cat = category_map[cat]
+ pos = position_map[pos]
+ indic_data[k] = (cat, pos, block)
+
+for k,new_cat in category_overrides.items():
+ (cat, pos, _) = indic_data.get(k, defaults)
+ indic_data[k] = (new_cat, pos, unicode_data[2][k])
+
+# We only expect position for certain types
+positioned_categories = ('CM', 'SM', 'RS', 'H', 'M', 'MPst')
+for k, (cat, pos, block) in indic_data.items():
+ if cat not in positioned_categories:
+ pos = 'END'
+ indic_data[k] = (cat, pos, block)
+
+# Position overrides are more complicated
+
+# Keep in sync with CONSONANT_FLAGS in the shaper
+consonant_categories = ('C', 'CS', 'Ra','CM', 'V', 'PLACEHOLDER', 'DOTTEDCIRCLE')
+matra_categories = ('M', 'MPst')
+smvd_categories = ('SM', 'VD', 'A', 'Symbol')
+for k, (cat, pos, block) in indic_data.items():
+ if cat in consonant_categories:
+ pos = 'BASE_C'
+ elif cat in matra_categories:
+ if block.startswith('Khmer') or block.startswith('Myanmar'):
+ cat = position_to_category(pos)
+ else:
+ pos = indic_matra_position(k, pos, block)
+ elif cat in smvd_categories:
+ pos = 'SMVD';
+ indic_data[k] = (cat, pos, block)
+
+for k,new_pos in position_overrides.items():
+ (cat, pos, _) = indic_data.get(k, defaults)
+ indic_data[k] = (cat, new_pos, unicode_data[2][k])
+
+
+values = [{_: 1} for _ in defaults]
+for vv in indic_data.values():
+ for i,v in enumerate(vv):
+ values[i][v] = values[i].get (v, 0) + 1
+
+
+
# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
singles = {}
for u in ALLOWED_SINGLES:
- singles[u] = data[u]
- del data[u]
+ singles[u] = indic_data[u]
+ del indic_data[u]
print ("/* == Start of generated table == */")
print ("/*")
@@ -106,37 +502,63 @@ print ('#include "hb.hh"')
print ()
print ('#ifndef HB_NO_OT_SHAPE')
print ()
-print ('#include "hb-ot-shape-complex-indic.hh"')
+print ('#include "hb-ot-shaper-indic.hh"')
+print ()
+print ('#pragma GCC diagnostic push')
+print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
+print ()
+
+# Print categories
+for shaper in categories:
+ print ('#include "hb-ot-shaper-%s-machine.hh"' % shaper)
+print ()
+done = {}
+for shaper, shaper_cats in categories.items():
+ print ('/* %s */' % shaper)
+ for cat in shaper_cats:
+ v = shaper[0].upper()
+ if cat not in done:
+ print ("#define OT_%s %s_Cat(%s)" % (cat, v, cat))
+ done[cat] = v
+ else:
+ print ('static_assert (OT_%s == %s_Cat(%s), "");' % (cat, v, cat))
print ()
# Shorten values
short = [{
- "Bindu": 'Bi',
- "Cantillation_Mark": 'Ca',
- "Joiner": 'ZWJ',
- "Non_Joiner": 'ZWNJ',
- "Number": 'Nd',
- "Visarga": 'Vs',
- "Vowel": 'Vo',
- "Vowel_Dependent": 'M',
- "Consonant_Prefixed": 'CPrf',
- "Other": 'x',
+ "Repha": 'Rf',
+ "PLACEHOLDER": 'GB',
+ "DOTTEDCIRCLE": 'DC',
+ "VPst": 'VR',
+ "VPre": 'VL',
+ "Robatic": 'Rt',
+ "Xgroup": 'Xg',
+ "Ygroup": 'Yg',
+ "As": 'As',
},{
- "Not_Applicable": 'x',
+ "END": 'X',
+ "BASE_C": 'C',
+ "ABOVE_C": 'T',
+ "BELOW_C": 'B',
+ "POST_C": 'R',
+ "PRE_C": 'L',
+ "PRE_M": 'LM',
+ "AFTER_MAIN": 'A',
+ "AFTER_SUB": 'AS',
+ "BEFORE_SUB": 'BS',
+ "AFTER_POST": 'AP',
+ "SMVD": 'SM',
}]
all_shorts = [{},{}]
# Add some of the values, to make them more readable, and to avoid duplicates
-
for i in range (2):
for v,s in short[i].items ():
all_shorts[i][s] = v
-what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
-what_short = ["ISC", "IMC"]
-print ('#pragma GCC diagnostic push')
-print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
+what = ["OT", "POS"]
+what_short = ["_OT", "_POS"]
cat_defs = []
for i in range (2):
vv = sorted (values[i].keys ())
@@ -150,7 +572,7 @@ for i in range (2):
raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
all_shorts[i][s] = v
short[i][v] = s
- cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + v.upper (), str (values[i][v]), v))
+ cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + (v.upper () if i else v), str (values[i][v]), v))
maxlen_s = max ([len (c[0]) for c in cat_defs])
maxlen_l = max ([len (c[1]) for c in cat_defs])
@@ -163,7 +585,9 @@ for s in what_short:
print ()
print ('#pragma GCC diagnostic pop')
print ()
-print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
+print ("#define INDIC_COMBINE_CATEGORIES(S,M) ((S) | ((M) << 8))")
+print ()
+print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (%s_##S, %s_##M)" % tuple(what_short))
print ()
print ()
@@ -193,7 +617,7 @@ def print_block (block, start, end, data):
if block:
last_block = block
-uu = sorted (data.keys ())
+uu = sorted (indic_data)
last = -100000
num = 0
@@ -204,17 +628,17 @@ print ("static const uint16_t indic_table[] = {")
for u in uu:
if u <= last:
continue
- block = data[u][2]
+ block = indic_data[u][2]
start = u//8*8
end = start+1
- while end in uu and block == data[end][2]:
+ while end in uu and block == indic_data[end][2]:
end += 1
end = (end-1)//8*8 + 7
if start != last + 1:
- if start - last <= 1+16*3:
- print_block (None, last+1, start-1, data)
+ if start - last <= 1+16*2:
+ print_block (None, last+1, start-1, indic_data)
else:
if last >= 0:
ends.append (last + 1)
@@ -224,7 +648,7 @@ for u in uu:
print ("#define indic_offset_0x%04xu %d" % (start, offset))
starts.append (start)
- print_block (block, start, end, data)
+ print_block (block, start, end, indic_data)
last = end
ends.append (last + 1)
offset += ends[-1] - starts[-1]
@@ -254,10 +678,11 @@ for p in sorted(pages):
print (" default:")
print (" break;")
print (" }")
-print (" return _(x,x);")
+print (" return _(X,X);")
print ("}")
print ()
print ("#undef _")
+print ("#undef INDIC_COMBINE_CATEGORIES")
for i in range (2):
print ()
vv = sorted (values[i].keys ())
@@ -269,6 +694,6 @@ print ('#endif')
print ()
print ("/* == End of generated table == */")
-# Maintain at least 30% occupancy in the table */
-if occupancy < 30:
+# Maintain at least 50% occupancy in the table */
+if occupancy < 50:
raise Exception ("Table too sparse, please investigate: ", occupancy)
diff --git a/src/gen-os2-unicode-ranges.py b/src/gen-os2-unicode-ranges.py
index 21aa1b9c0..b1a34d478 100755
--- a/src/gen-os2-unicode-ranges.py
+++ b/src/gen-os2-unicode-ranges.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
-Input is a tab seperated list of unicode ranges from the otspec
+Input is a tab separated list of unicode ranges from the otspec
(https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
"""
diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py
index d1b5d4342..7e15c08c5 100755
--- a/src/gen-tag-table.py
+++ b/src/gen-tag-table.py
@@ -329,6 +329,10 @@ class OpenTypeRegistryParser (HTMLParser):
from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47``
inverted. Its values start as unsorted sets;
``sort_languages`` converts them to sorted lists.
+ from_bcp_47_uninherited (Optional[Dict[str, AbstractSet[str]]]):
+ A copy of ``from_bcp_47``. It starts as ``None`` and is
+ populated at the beginning of the first call to
+ ``inherit_from_macrolanguages``.
"""
def __init__ (self):
@@ -338,13 +342,18 @@ class OpenTypeRegistryParser (HTMLParser):
self.ranks = collections.defaultdict (int)
self.to_bcp_47 = collections.defaultdict (set)
self.from_bcp_47 = collections.defaultdict (set)
+ self.from_bcp_47_uninherited = None
# Whether the parser is in a <td> element
self._td = False
+ # Whether the parser is after a <br> element within the current <tr> element
+ self._br = False
# The text of the <td> elements of the current <tr> element.
self._current_tr = []
def handle_starttag (self, tag, attrs):
- if tag == 'meta':
+ if tag == 'br':
+ self._br = True
+ elif tag == 'meta':
for attr, value in attrs:
if attr == 'name' and value == 'updated_at':
self.header = self.get_starttag_text ()
@@ -353,6 +362,7 @@ class OpenTypeRegistryParser (HTMLParser):
self._td = True
self._current_tr.append ('')
elif tag == 'tr':
+ self._br = False
self._current_tr = []
def handle_endtag (self, tag):
@@ -377,7 +387,7 @@ class OpenTypeRegistryParser (HTMLParser):
self.ranks[tag] = rank
def handle_data (self, data):
- if self._td:
+ if self._td and not self._br:
self._current_tr[-1] += data
def handle_charref (self, name):
@@ -457,30 +467,51 @@ class OpenTypeRegistryParser (HTMLParser):
explicit mapping, so it inherits from sq (Albanian) the mapping
to SQI.
+ However, if an OpenType tag maps to a BCP 47 macrolanguage and
+ some but not all of its individual languages, the mapping is not
+ inherited from the macrolanguage to the missing individual
+ languages. For example, INUK (Nunavik Inuktitut) is mapped to
+ ike (Eastern Canadian Inuktitut) and iu (Inuktitut) but not to
+ ikt (Inuinnaqtun, which is an individual language of iu), so
+ this method does not add a mapping from ikt to INUK.
+
If a BCP 47 tag for a macrolanguage has no OpenType mapping but
- all of its individual languages do and they all map to the same
- tags, the mapping is copied to the macrolanguage.
+ some of its individual languages do, their mappings are copied
+ to the macrolanguage.
"""
global bcp_47
- original_ot_from_bcp_47 = dict (self.from_bcp_47)
+ first_time = self.from_bcp_47_uninherited is None
+ if first_time:
+ self.from_bcp_47_uninherited = dict (self.from_bcp_47)
for macrolanguage, languages in dict (bcp_47.macrolanguages).items ():
- ot_macrolanguages = set (original_ot_from_bcp_47.get (macrolanguage, set ()))
+ ot_macrolanguages = {
+ ot_macrolanguage for ot_macrolanguage in self.from_bcp_47_uninherited.get (macrolanguage, set ())
+ }
+ blocked_ot_macrolanguages = set ()
+ if 'retired code' not in bcp_47.scopes.get (macrolanguage, ''):
+ for ot_macrolanguage in ot_macrolanguages:
+ round_trip_macrolanguages = {
+ l for l in self.to_bcp_47[ot_macrolanguage]
+ if 'retired code' not in bcp_47.scopes.get (l, '')
+ }
+ round_trip_languages = {
+ l for l in languages
+ if 'retired code' not in bcp_47.scopes.get (l, '')
+ }
+ intersection = round_trip_macrolanguages & round_trip_languages
+ if intersection and intersection != round_trip_languages:
+ blocked_ot_macrolanguages.add (ot_macrolanguage)
if ot_macrolanguages:
for ot_macrolanguage in ot_macrolanguages:
- for language in languages:
- self.add_language (language, ot_macrolanguage)
- self.ranks[ot_macrolanguage] += 1
- else:
+ if ot_macrolanguage not in blocked_ot_macrolanguages:
+ for language in languages:
+ self.add_language (language, ot_macrolanguage)
+ if not blocked_ot_macrolanguages:
+ self.ranks[ot_macrolanguage] += 1
+ elif first_time:
for language in languages:
- if language in original_ot_from_bcp_47:
- if ot_macrolanguages:
- ml = original_ot_from_bcp_47[language]
- if ml:
- ot_macrolanguages &= ml
- else:
- pass
- else:
- ot_macrolanguages |= original_ot_from_bcp_47[language]
+ if language in self.from_bcp_47_uninherited:
+ ot_macrolanguages |= self.from_bcp_47_uninherited[language]
else:
ot_macrolanguages.clear ()
if not ot_macrolanguages:
@@ -565,7 +596,7 @@ class BCP47Parser (object):
if scope == 'macrolanguage':
scope = ' [macrolanguage]'
elif scope == 'collection':
- scope = ' [family]'
+ scope = ' [collection]'
else:
continue
self.scopes[subtag] = scope
@@ -704,10 +735,13 @@ ot.ranks['MLR'] += 1
bcp_47.names['mhv'] = 'Arakanese'
bcp_47.scopes['mhv'] = ' (retired code)'
+ot.add_language ('mnw-TH', 'MONT')
+
ot.add_language ('no', 'NOR')
ot.add_language ('oc-provenc', 'PRO')
+ot.remove_language_ot ('QUZ')
ot.add_language ('qu', 'QUZ')
ot.add_language ('qub', 'QWH')
ot.add_language ('qud', 'QVI')
@@ -740,7 +774,6 @@ ot.add_language ('qxr', 'QVI')
ot.add_language ('qxt', 'QWH')
ot.add_language ('qxw', 'QWH')
-bcp_47.macrolanguages['ro'].remove ('mo')
bcp_47.macrolanguages['ro-MD'].add ('mo')
ot.remove_language_ot ('SYRE')
@@ -861,7 +894,6 @@ print ()
print ('#ifndef HB_OT_TAG_TABLE_HH')
print ('#define HB_OT_TAG_TABLE_HH')
print ()
-print ('static const LangTag ot_languages[] = {')
def hb_tag (tag):
"""Convert a tag to ``HB_TAG`` form.
@@ -911,33 +943,39 @@ def get_matching_language_name (intersection, candidates):
def same_tag (bcp_47_tag, ot_tags):
return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
-for language, tags in sorted (ot.from_bcp_47.items ()):
- if language == '' or '-' in language:
- continue
- commented_out = same_tag (language, tags)
- for i, tag in enumerate (tags, start=1):
- print ('%s{\"%s\",\t%s},' % ('/*' if commented_out else ' ', language, hb_tag (tag)), end='')
- if commented_out:
- print ('*/', end='')
- print ('\t/* ', end='')
- bcp_47_name = bcp_47.names.get (language, '')
- bcp_47_name_candidates = bcp_47_name.split ('\n')
- ot_name = ot.names[tag]
- scope = bcp_47.scopes.get (language, '')
- if tag == DEFAULT_LANGUAGE_SYSTEM:
- write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
- else:
- intersection = language_name_intersection (bcp_47_name, ot_name)
- if not intersection:
- write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
+for language_len in (2, 3):
+ if language_len == 3:
+ print ('#ifndef HB_NO_LANGUAGE_LONG')
+ print ('static const LangTag ot_languages%d[] = {' % language_len)
+ for language, tags in sorted (ot.from_bcp_47.items ()):
+ if language == '' or '-' in language:
+ continue
+ if len(language) != language_len: continue
+ commented_out = same_tag (language, tags)
+ for i, tag in enumerate (tags, start=1):
+ print ('%s{%s,\t%s},' % ('/*' if commented_out else ' ', hb_tag (language), hb_tag (tag)), end='')
+ if commented_out:
+ print ('*/', end='')
+ print ('\t/* ', end='')
+ bcp_47_name = bcp_47.names.get (language, '')
+ bcp_47_name_candidates = bcp_47_name.split ('\n')
+ ot_name = ot.names[tag]
+ scope = bcp_47.scopes.get (language, '')
+ if tag == DEFAULT_LANGUAGE_SYSTEM:
+ write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
else:
- name = get_matching_language_name (intersection, bcp_47_name_candidates)
- bcp_47.names[language] = name
- write ('%s%s' % (name if len (name) > len (ot_name) else ot_name, scope))
- print (' */')
-
-print ('};')
-print ()
+ intersection = language_name_intersection (bcp_47_name, ot_name)
+ if not intersection:
+ write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
+ else:
+ name = get_matching_language_name (intersection, bcp_47_name_candidates)
+ bcp_47.names[language] = name
+ write ('%s%s' % (name if len (name) > len (ot_name) else ot_name, scope))
+ print (' */')
+ print ('};')
+ if language_len == 3:
+ print ('#endif')
+ print ()
print ('/**')
print (' * hb_ot_tags_from_complex_language:')
@@ -953,19 +991,19 @@ print (' * Converts a multi-subtag BCP 47 language tag to language tags.')
print (' *')
print (' * Return value: Whether any language systems were retrieved.')
print (' **/')
-print ('static bool')
+print ('static inline bool')
print ('hb_ot_tags_from_complex_language (const char *lang_str,')
print ('\t\t\t\t const char *limit,')
print ('\t\t\t\t unsigned int *count /* IN/OUT */,')
print ('\t\t\t\t hb_tag_t *tags /* OUT */)')
print ('{')
-def print_subtag_matches (subtag, new_line):
+def print_subtag_matches (subtag, string, new_line):
if subtag:
if new_line:
print ()
print ('\t&& ', end='')
- print ('subtag_matches (lang_str, limit, "-%s")' % subtag, end='')
+ print ('subtag_matches (%s, limit, "-%s", %i)' % (string, subtag, 1 + len (subtag)), end='')
complex_tags = collections.defaultdict (list)
for initial, group in itertools.groupby ((lt_tags for lt_tags in [
@@ -976,36 +1014,58 @@ for initial, group in itertools.groupby ((lt_tags for lt_tags in [
key=lambda lt_tags: lt_tags[0].get_group ()):
complex_tags[initial] += group
+# Calculate the min length of the subtags outside the switch
+min_subtag_len = 100
+for initial, items in sorted (complex_tags.items ()):
+ if initial != 'und':
+ continue
+ for lt, tags in items:
+ if not tags:
+ continue
+ subtag_len = 0
+ subtag_len += 1 + len (lt.script) if lt.script is not None else 0
+ subtag_len += 1 + len (lt.region) if lt.region is not None else 0
+ subtag_len += 1 + len (lt.variant) if lt.variant is not None else 0
+ min_subtag_len = min(subtag_len, min_subtag_len)
+
+print (' if (limit - lang_str >= %d)' % (min_subtag_len + 2))
+print (' {')
+print (" const char *p = strchr (lang_str, '-');")
+print (" if (!p || p >= limit || limit - p < %i) goto out;" % min_subtag_len)
for initial, items in sorted (complex_tags.items ()):
if initial != 'und':
continue
for lt, tags in items:
+ if not tags:
+ continue
if lt.variant in bcp_47.prefixes:
expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language,
'%s is not a valid prefix of %s' % (lt.language, lt.variant))
- print (' if (', end='')
- print_subtag_matches (lt.script, False)
- print_subtag_matches (lt.region, False)
- print_subtag_matches (lt.variant, False)
+ print (' if (', end='')
+ print_subtag_matches (lt.script, 'p', False)
+ print_subtag_matches (lt.region, 'p', False)
+ print_subtag_matches (lt.variant, 'p', False)
print (')')
- print (' {')
- write (' /* %s */' % bcp_47.get_name (lt))
+ print (' {')
+ write (' /* %s */' % bcp_47.get_name (lt))
print ()
if len (tags) == 1:
- write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
+ write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
print ()
- print (' *count = 1;')
+ print (' *count = 1;')
else:
print (' hb_tag_t possible_tags[] = {')
for tag in tags:
write (' %s, /* %s */' % (hb_tag (tag), ot.names[tag]))
print ()
- print (' };')
- print (' for (i = 0; i < %s && i < *count; i++)' % len (tags))
- print (' tags[i] = possible_tags[i];')
- print (' *count = i;')
- print (' return true;')
- print (' }')
+ print (' };')
+ print (' for (i = 0; i < %s && i < *count; i++)' % len (tags))
+ print ('\ttags[i] = possible_tags[i];')
+ print (' *count = i;')
+ print (' return true;')
+ print (' }')
+print (' }')
+print ('out:')
print (' switch (lang_str[0])')
print (' {')
@@ -1014,6 +1074,8 @@ for initial, items in sorted (complex_tags.items ()):
continue
print (" case '%s':" % initial)
for lt, tags in items:
+ if not tags:
+ continue
print (' if (', end='')
script = lt.script
region = lt.region
@@ -1030,10 +1092,10 @@ for initial, items in sorted (complex_tags.items ()):
if string_literal[-1] == '-':
print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='')
else:
- print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='')
- print_subtag_matches (script, True)
- print_subtag_matches (region, True)
- print_subtag_matches (lt.variant, True)
+ print ('lang_matches (&lang_str[1], limit, "%s", %i)' % (string_literal, len (string_literal)), end='')
+ print_subtag_matches (script, 'lang_str', True)
+ print_subtag_matches (region, 'lang_str', True)
+ print_subtag_matches (lt.variant, 'lang_str', True)
print (')')
print (' {')
write (' /* %s */' % bcp_47.get_name (lt))
@@ -1072,7 +1134,7 @@ print (' *')
print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
print (' **/')
-print ('static hb_language_t')
+print ('static inline hb_language_t')
print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)')
print ('{')
print (' switch (tag)')
@@ -1114,9 +1176,13 @@ def verify_disambiguation_dict ():
elif len (primary_tags) == 0:
expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag)
else:
- macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]')
+ original_languages = [t for t in primary_tags if t in ot.from_bcp_47_uninherited and 'retired code' not in bcp_47.scopes.get (t, '')]
+ if len (original_languages) == 1:
+ macrolanguages = original_languages
+ else:
+ macrolanguages = [t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]']
if len (macrolanguages) != 1:
- macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [family]')
+ macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [collection]')
if len (macrolanguages) != 1:
macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, ''))
if len (macrolanguages) != 1:
diff --git a/src/gen-ucd-table.py b/src/gen-ucd-table.py
index 35fba2d07..d85ae4faa 100755
--- a/src/gen-ucd-table.py
+++ b/src/gen-ucd-table.py
@@ -25,14 +25,28 @@ hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
logging.info('Preparing data tables...')
+
+# This is how the data is encoded:
+#
+# General_Category (gc), Canonical_Combining_Class (ccc),
+# and Script (sc) are encoded as integers.
+#
+# Mirroring character (bmg) is encoded as difference from
+# the original character.
+#
+# Composition & Decomposition (dm) are encoded elaborately,
+# as discussed below.
+
gc = [u['gc'] for u in ucd]
ccc = [int(u['ccc']) for u in ucd]
bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
-#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
-#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)
-
sc = [u['sc'] for u in ucd]
+
+# Prepare Compose / Decompose data
+#
+# This code is very dense. See hb_ucd_compose() / hb_ucd_decompose() for the logic.
+
dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
@@ -63,6 +77,9 @@ dm_order = {None: 0}
dm_order.update(dm1_order)
dm_order.update(dm2_order)
+
+# Prepare General_Category / Script mapping arrays
+
gc_order = dict()
for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
@@ -83,10 +100,18 @@ for line in open(hb_common_h):
sc_order[i] = tag
sc_array.append(name)
-DEFAULT = 1
-COMPACT = 3
-SLOPPY = 5
+# Write out main data
+
+DEFAULT = 'DEFAULT'
+COMPACT = 'COMPACT'
+SLOPPY = 'SLOPPY'
+
+compression_level = {
+ DEFAULT: 5,
+ COMPACT: 9,
+ SLOPPY: 9,
+}
logging.info('Generating output...')
print("/* == Start of generated table == */")
@@ -104,6 +129,9 @@ print()
print('#include "hb.hh"')
print()
+
+# Write mapping data
+
code = packTab.Code('_hb_ucd')
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
@@ -120,18 +148,24 @@ datasets = [
('dm', dm, None, dm_order),
]
-for compression in (DEFAULT, COMPACT, SLOPPY):
+
+# Write main data
+
+for step in (DEFAULT, COMPACT, SLOPPY):
+ compression = compression_level[step]
logging.info(' Compression=%d:' % compression)
print()
- if compression == DEFAULT:
+ if step == DEFAULT:
print('#ifndef HB_OPTIMIZE_SIZE')
- elif compression == COMPACT:
+ elif step == COMPACT:
print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
- else:
+ elif step == SLOPPY:
print('#else')
+ else:
+ assert False
print()
- if compression == SLOPPY:
+ if step == SLOPPY:
for i in range(len(gc)):
if (i % 128) and gc[i] == 'Cn':
gc[i] = gc[i - 1]
@@ -157,6 +191,7 @@ for compression in (DEFAULT, COMPACT, SLOPPY):
print()
+
print('#endif')
print()
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index 34540ca6d..e8b76dfb5 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python3
# flake8: noqa: F821
+import logging
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+
"""usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
Input files:
@@ -39,7 +42,7 @@ for j in range(7, 9):
headers[j - 1].append(line)
headers.append (["UnicodeData.txt does not have a header."])
-data = [{} for _ in files]
+unicode_data = [{} for _ in files]
values = [{} for _ in files]
for i, f in enumerate (files):
for line in f:
@@ -73,38 +76,16 @@ for i, f in enumerate (files):
i0 = i if i < 7 else i - 7
for u in range (start, end + 1):
- data[i0][u] = t
+ unicode_data[i0][u] = t
values[i0][t] = values[i0].get (t, 0) + end - start + 1
defaults = ('Other', 'Not_Applicable', 'jt_X', '', 'Cn', 'No_Block', 'Unknown')
-# TODO Characters that are not in Unicode Indic files, but used in USE
-data[0][0x1B61] = defaults[0]
-data[0][0x1B63] = defaults[0]
-data[0][0x1B64] = defaults[0]
-data[0][0x1B65] = defaults[0]
-data[0][0x1B66] = defaults[0]
-data[0][0x1B67] = defaults[0]
-data[0][0x1B69] = defaults[0]
-data[0][0x1B6A] = defaults[0]
-data[0][0x2060] = defaults[0]
-# TODO https://github.com/harfbuzz/harfbuzz/pull/1685
-data[0][0x1B5B] = 'Consonant_Placeholder'
-data[0][0x1B5C] = 'Consonant_Placeholder'
-data[0][0x1B5F] = 'Consonant_Placeholder'
-data[0][0x1B62] = 'Consonant_Placeholder'
-data[0][0x1B68] = 'Consonant_Placeholder'
-# TODO https://github.com/harfbuzz/harfbuzz/issues/1035
-data[0][0x11C44] = 'Consonant_Placeholder'
-data[0][0x11C45] = 'Consonant_Placeholder'
-# TODO https://github.com/harfbuzz/harfbuzz/pull/1399
-data[0][0x111C8] = 'Consonant_Placeholder'
-
# Merge data into one dict:
for i,v in enumerate (defaults):
values[i][v] = values[i].get (v, 0) + 1
combined = {}
-for i,d in enumerate (data):
+for i,d in enumerate (unicode_data):
for u,v in d.items ():
if not u in combined:
if i >= 4:
@@ -112,8 +93,6 @@ for i,d in enumerate (data):
combined[u] = list (defaults)
combined[u][i] = v
combined = {k: v for k, v in combined.items() if v[6] not in DISABLED_SCRIPTS}
-data = combined
-del combined
property_names = [
@@ -158,6 +137,7 @@ property_names = [
'Number_Joiner',
'Number',
'Brahmi_Joining_Number',
+ 'Symbol_Modifier',
'Hieroglyph',
'Hieroglyph_Joiner',
'Hieroglyph_Segment_Begin',
@@ -226,8 +206,8 @@ def is_BASE_OTHER(U, UISC, UDI, UGC, AJT):
if UISC == Consonant_Placeholder: return True
return U in [0x2015, 0x2022, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
def is_CGJ(U, UISC, UDI, UGC, AJT):
- # Also includes VARIATION_SELECTOR, WJ, and ZWJ
- return U == 0x200D or UDI and UGC in [Mc, Me, Mn]
+ # Also includes VARIATION_SELECTOR and ZWJ
+ return UISC == Joiner or UDI and UGC in [Mc, Me, Mn]
def is_CONS_FINAL(U, UISC, UDI, UGC, AJT):
return ((UISC == Consonant_Final and UGC != Lo) or
UISC == Consonant_Succeeding_Repha)
@@ -238,20 +218,16 @@ def is_CONS_MED(U, UISC, UDI, UGC, AJT):
return (UISC == Consonant_Medial and UGC != Lo or
UISC == Consonant_Initial_Postfixed)
def is_CONS_MOD(U, UISC, UDI, UGC, AJT):
- return (UISC in [Nukta, Gemination_Mark, Consonant_Killer] and
- not is_SYM_MOD(U, UISC, UDI, UGC, AJT))
+ return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
def is_CONS_SUB(U, UISC, UDI, UGC, AJT):
return UISC == Consonant_Subjoined and UGC != Lo
def is_CONS_WITH_STACKER(U, UISC, UDI, UGC, AJT):
return UISC == Consonant_With_Stacker
def is_HALANT(U, UISC, UDI, UGC, AJT):
- return (UISC in [Virama, Invisible_Stacker]
- and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT)
- and not is_SAKOT(U, UISC, UDI, UGC, AJT))
+ return UISC == Virama and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT)
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT):
# Split off of HALANT
- # https://github.com/harfbuzz/harfbuzz/issues/1379
- return U == 0x1134D
+ return U == 0x0DCA
def is_HALANT_NUM(U, UISC, UDI, UGC, AJT):
return UISC == Number_Joiner
def is_HIEROGLYPH(U, UISC, UDI, UGC, AJT):
@@ -262,15 +238,21 @@ def is_HIEROGLYPH_SEGMENT_BEGIN(U, UISC, UDI, UGC, AJT):
return UISC == Hieroglyph_Segment_Begin
def is_HIEROGLYPH_SEGMENT_END(U, UISC, UDI, UGC, AJT):
return UISC == Hieroglyph_Segment_End
+def is_INVISIBLE_STACKER(U, UISC, UDI, UGC, AJT):
+ # Split off of HALANT
+ return (UISC == Invisible_Stacker
+ and not is_SAKOT(U, UISC, UDI, UGC, AJT)
+ )
def is_ZWNJ(U, UISC, UDI, UGC, AJT):
return UISC == Non_Joiner
def is_OTHER(U, UISC, UDI, UGC, AJT):
- # Also includes BASE_IND, Rsv, and SYM
- return ((UGC in [Cn, Po] or UISC in [Consonant_Dead, Joiner, Modifying_Letter, Other])
+ # Also includes BASE_IND and SYM
+ return ((UGC == Po or UISC in [Consonant_Dead, Joiner, Modifying_Letter, Other])
and not is_BASE(U, UISC, UDI, UGC, AJT)
and not is_BASE_OTHER(U, UISC, UDI, UGC, AJT)
and not is_CGJ(U, UISC, UDI, UGC, AJT)
and not is_SYM_MOD(U, UISC, UDI, UGC, AJT)
+ and not is_Word_Joiner(U, UISC, UDI, UGC, AJT)
)
def is_REPHA(U, UISC, UDI, UGC, AJT):
return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
@@ -278,15 +260,19 @@ def is_SAKOT(U, UISC, UDI, UGC, AJT):
# Split off of HALANT
return U == 0x1A60
def is_SYM_MOD(U, UISC, UDI, UGC, AJT):
- return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
+ return UISC == Symbol_Modifier
def is_VOWEL(U, UISC, UDI, UGC, AJT):
- # https://github.com/harfbuzz/harfbuzz/issues/376
return (UISC == Pure_Killer or
- (UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
+ UGC != Lo and UISC in [Vowel, Vowel_Dependent])
def is_VOWEL_MOD(U, UISC, UDI, UGC, AJT):
- # https://github.com/harfbuzz/harfbuzz/issues/376
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
- (UGC != Lo and (UISC == Bindu or U in [0xAA29])))
+ UGC != Lo and UISC == Bindu)
+def is_Word_Joiner(U, UISC, UDI, UGC, AJT):
+ # Also includes Rsv
+ return (UDI and U not in [0x115F, 0x1160, 0x3164, 0xFFA0, 0x1BCA0, 0x1BCA1, 0x1BCA2, 0x1BCA3]
+ and UISC == Other
+ and not is_CGJ(U, UISC, UDI, UGC, AJT)
+ ) or UGC == Cn
use_mapping = {
'B': is_BASE,
@@ -302,6 +288,7 @@ use_mapping = {
'H': is_HALANT,
'HVM': is_HALANT_OR_VOWEL_MODIFIER,
'HN': is_HALANT_NUM,
+ 'IS': is_INVISIBLE_STACKER,
'G': is_HIEROGLYPH,
'J': is_HIEROGLYPH_JOINER,
'SB': is_HIEROGLYPH_SEGMENT_BEGIN,
@@ -313,6 +300,7 @@ use_mapping = {
'SM': is_SYM_MOD,
'V': is_VOWEL,
'VM': is_VOWEL_MOD,
+ 'WJ': is_Word_Joiner,
}
use_positions = {
@@ -349,6 +337,7 @@ use_positions = {
},
'H': None,
'HVM': None,
+ 'IS': None,
'B': None,
'FM': {
'Abv': [Top],
@@ -373,36 +362,19 @@ def map_to_use(data):
# TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC
if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
- # TODO: https://github.com/harfbuzz/harfbuzz/pull/627
- if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
-
# TODO: U+1CED should only be allowed after some of
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
if U == 0x1CED: UISC = Tone_Mark
- # TODO: https://github.com/microsoft/font-tools/issues/1
- if U == 0xA982: UISC = Consonant_Succeeding_Repha
-
values = [k for k,v in items if v(U, UISC, UDI, UGC, AJT)]
assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UISC, UDI, UGC, AJT, values)
USE = values[0]
# Resolve Indic_Positional_Category
- # TODO: These should die, but have UIPC in Unicode 13.0.0
- if U in [0x953, 0x954]: UIPC = Not_Applicable
-
- # TODO: These are not in USE's override list that we have, nor are they in Unicode 13.0.0
- if 0xA926 <= U <= 0xA92A: UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
# and https://github.com/harfbuzz/harfbuzz/issues/1631
if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
- if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
-
- # TODO: https://github.com/harfbuzz/harfbuzz/pull/982
- # also https://github.com/harfbuzz/harfbuzz/issues/1012
- if 0x1112A <= U <= 0x1112B: UIPC = Top
- if 0x11131 <= U <= 0x11132: UIPC = Top
assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or
USE in use_positions), "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT)
@@ -416,8 +388,7 @@ def map_to_use(data):
out[U] = (USE, UBlock)
return out
-defaults = ('O', 'No_Block')
-data = map_to_use(data)
+use_data = map_to_use(combined)
print ("/* == Start of generated table == */")
print ("/*")
@@ -432,18 +403,18 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH")
+print ("#ifndef HB_OT_SHAPER_USE_TABLE_HH")
+print ("#define HB_OT_SHAPER_USE_TABLE_HH")
print ()
print ('#include "hb.hh"')
print ()
-print ('#include "hb-ot-shape-complex-use-machine.hh"')
+print ('#include "hb-ot-shaper-use-machine.hh"')
print ()
total = 0
used = 0
last_block = None
-def print_block (block, start, end, data):
+def print_block (block, start, end, use_data):
global total, used, last_block
if block and block != last_block:
print ()
@@ -458,17 +429,23 @@ def print_block (block, start, end, data):
if u % 16 == 0:
print ()
print (" /* %04X */" % u, end='')
- if u in data:
+ if u in use_data:
num += 1
- d = data.get (u, defaults)
- print ("%6s," % d[0], end='')
+ d = use_data.get (u)
+ if d is not None:
+ d = d[0]
+ elif u in unicode_data[4]:
+ d = 'O'
+ else:
+ d = 'WJ'
+ print ("%6s," % d, end='')
total += end - start + 1
used += num
if block:
last_block = block
-uu = sorted (data.keys ())
+uu = sorted (use_data.keys ())
last = -100000
num = 0
@@ -487,61 +464,34 @@ for k,v in sorted(use_positions.items()):
print ("#define %s USE(%s)" % (tag, tag))
print ('#pragma GCC diagnostic pop')
print ("")
-print ("static const uint8_t use_table[] = {")
-for u in uu:
- if u <= last:
- continue
- if data[u][0] == 'O':
- continue
- block = data[u][1]
-
- start = u//8*8
- end = start+1
- while end in uu and block == data[end][1]:
- end += 1
- end = (end-1)//8*8 + 7
-
- if start != last + 1:
- if start - last <= 1+16*3:
- print_block (None, last+1, start-1, data)
- else:
- if last >= 0:
- ends.append (last + 1)
- offset += ends[-1] - starts[-1]
- print ()
- print ()
- print ("#define use_offset_0x%04xu %d" % (start, offset))
- starts.append (start)
- print_block (block, start, end, data)
- last = end
-ends.append (last + 1)
-offset += ends[-1] - starts[-1]
-print ()
-print ()
-occupancy = used * 100. / total
-page_bits = 12
-print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
-print ()
-print ("static inline uint8_t")
-print ("hb_use_get_category (hb_codepoint_t u)")
-print ("{")
-print (" switch (u >> %d)" % page_bits)
-print (" {")
-pages = set([u>>page_bits for u in starts+ends])
-for p in sorted(pages):
- print (" case 0x%0Xu:" % p)
- for (start,end) in zip (starts, ends):
- if p not in [start>>page_bits, end>>page_bits]: continue
- offset = "use_offset_0x%04xu" % start
- print (" if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
- print (" break;")
- print ("")
-print (" default:")
-print (" break;")
-print (" }")
-print (" return USE(O);")
-print ("}")
+
+import packTab
+data = {u:v[0] for u,v in use_data.items()}
+
+DEFAULT = 5
+COMPACT = 9
+for compression in (DEFAULT, COMPACT):
+
+ logging.info(' Compression=%d:' % compression)
+ print()
+ if compression == DEFAULT:
+ print('#ifndef HB_OPTIMIZE_SIZE')
+ elif compression == COMPACT:
+ print('#else')
+ else:
+ assert False
+ print()
+
+ code = packTab.Code('hb_use')
+ sol = packTab.pack_table(data, compression=compression, default='O')
+ logging.info(' FullCost=%d' % (sol.fullCost))
+ sol.genCode(code, f'get_category')
+ code.print_c(linkage='static inline')
+ print ()
+
+print('#endif')
+
print ()
for k in sorted(use_mapping.keys()):
if k in use_positions and use_positions[k]: continue
@@ -553,9 +503,5 @@ for k,v in sorted(use_positions.items()):
print ("#undef %s" % tag)
print ()
print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */")
+print ("#endif /* HB_OT_SHAPER_USE_TABLE_HH */")
print ("/* == End of generated table == */")
-
-# Maintain at least 50% occupancy in the table */
-if occupancy < 50:
- raise Exception ("Table too sparse, please investigate: ", occupancy)
diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py
index 184ec29cf..3c1f6211e 100755
--- a/src/gen-vowel-constraints.py
+++ b/src/gen-vowel-constraints.py
@@ -5,7 +5,7 @@
It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted
circles into sequences prohibited by the USE script development spec.
This function should be used as the ``preprocess_text`` of an
-``hb_ot_complex_shaper_t``.
+``hb_ot_shaper_t``.
usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
@@ -166,7 +166,7 @@ print ('#include "hb.hh"')
print ()
print ('#ifndef HB_NO_OT_SHAPE')
print ()
-print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
+print ('#include "hb-ot-shaper-vowel-constraints.hh"')
print ()
print ('static void')
print ('_output_dotted_circle (hb_buffer_t *buffer)')
@@ -188,7 +188,7 @@ print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB
print ('\t\t\t\t hb_buffer_t *buffer,')
print ('\t\t\t\t hb_font_t *font HB_UNUSED)')
print ('{')
-print ('#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS')
+print ('#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS')
print (' return;')
print ('#endif')
print (' if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
@@ -220,7 +220,7 @@ for script, constraints in sorted (constraints.items (), key=lambda s_c: script_
print (' default:')
print (' break;')
print (' }')
-print (' buffer->swap_buffers ();')
+print (' buffer->sync ();')
print ('}')
print ()
diff --git a/src/graph/classdef-graph.hh b/src/graph/classdef-graph.hh
new file mode 100644
index 000000000..c2e24a706
--- /dev/null
+++ b/src/graph/classdef-graph.hh
@@ -0,0 +1,216 @@
+/*
+ * 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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-common.hh"
+
+#ifndef GRAPH_CLASSDEF_GRAPH_HH
+#define GRAPH_CLASSDEF_GRAPH_HH
+
+namespace graph {
+
+struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
+ }
+};
+
+struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+ }
+};
+
+struct ClassDef : public OT::ClassDef
+{
+ template<typename It>
+ static bool add_class_def (gsubgpos_graph_context_t& c,
+ unsigned parent_id,
+ unsigned link_position,
+ It glyph_and_class,
+ unsigned max_size)
+ {
+ unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr);
+ auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id];
+ if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size))
+ return false;
+
+ auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+ class_def_link->width = SmallTypes::size;
+ class_def_link->objidx = class_def_prime_id;
+ class_def_link->position = link_position;
+ class_def_prime_vertex.parents.push (parent_id);
+
+ return true;
+ }
+
+ template<typename It>
+ static bool make_class_def (gsubgpos_graph_context_t& c,
+ It glyph_and_class,
+ unsigned dest_obj,
+ unsigned max_size)
+ {
+ char* buffer = (char*) hb_calloc (1, max_size);
+ hb_serialize_context_t serializer (buffer, max_size);
+ OT::ClassDef_serialize (&serializer, glyph_and_class);
+ serializer.end_serialize ();
+ if (serializer.in_error ())
+ {
+ hb_free (buffer);
+ return false;
+ }
+
+ hb_bytes_t class_def_copy = serializer.copy_bytes ();
+ c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+ auto& obj = c.graph.vertices_[dest_obj].obj;
+ obj.head = (char *) class_def_copy.arrayZ;
+ obj.tail = obj.head + class_def_copy.length;
+
+ hb_free (buffer);
+ return true;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::ClassDef::min_size) return false;
+ switch (u.format)
+ {
+ case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
+ case 2: return ((ClassDefFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+ // Not currently supported
+ case 3:
+ case 4:
+#endif
+ default: return false;
+ }
+ }
+};
+
+
+struct class_def_size_estimator_t
+{
+ template<typename It>
+ class_def_size_estimator_t (It glyph_and_class)
+ : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+ {
+ unsigned last_gid = (unsigned) -1;
+ for (auto p : + glyph_and_class)
+ {
+ unsigned gid = p.first;
+ unsigned klass = p.second;
+
+ if (last_gid != (unsigned) -1 && gid != last_gid + 1)
+ gids_consecutive = false;
+ last_gid = gid;
+
+ hb_set_t* glyphs;
+ if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
+ glyphs->add (gid);
+ continue;
+ }
+
+ hb_set_t new_glyphs;
+ new_glyphs.add (gid);
+ glyphs_per_class.set (klass, std::move (new_glyphs));
+ }
+
+ if (in_error ()) return;
+
+ for (unsigned klass : glyphs_per_class.keys ())
+ {
+ if (!klass) continue; // class 0 doesn't get encoded.
+
+ const hb_set_t& glyphs = glyphs_per_class.get (klass);
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ unsigned count = 0;
+ while (glyphs.next_range (&start, &end))
+ count++;
+
+ num_ranges_per_class.set (klass, count);
+ }
+ }
+
+ // Incremental increase in the Coverage and ClassDef table size
+ // (worst case) if all glyphs associated with 'klass' were added.
+ unsigned incremental_coverage_size (unsigned klass) const
+ {
+ // Coverage takes 2 bytes per glyph worst case,
+ return 2 * glyphs_per_class.get (klass).get_population ();
+ }
+
+ // Incremental increase in the Coverage and ClassDef table size
+ // (worst case) if all glyphs associated with 'klass' were added.
+ unsigned incremental_class_def_size (unsigned klass) const
+ {
+ // ClassDef takes 6 bytes per range
+ unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
+ if (gids_consecutive)
+ {
+ // ClassDef1 takes 2 bytes per glyph, but only can be used
+ // when gids are consecutive.
+ return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+ }
+
+ return class_def_2_size;
+ }
+
+ bool in_error ()
+ {
+ if (num_ranges_per_class.in_error ()) return true;
+ if (glyphs_per_class.in_error ()) return true;
+
+ for (const hb_set_t& s : glyphs_per_class.values ())
+ {
+ if (s.in_error ()) return true;
+ }
+ return false;
+ }
+
+ private:
+ bool gids_consecutive;
+ hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
+ hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+};
+
+
+}
+
+#endif // GRAPH_CLASSDEF_GRAPH_HH
diff --git a/src/graph/coverage-graph.hh b/src/graph/coverage-graph.hh
new file mode 100644
index 000000000..49d093631
--- /dev/null
+++ b/src/graph/coverage-graph.hh
@@ -0,0 +1,152 @@
+/*
+ * 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
+ */
+
+#include "graph.hh"
+#include "../OT/Layout/Common/Coverage.hh"
+
+#ifndef GRAPH_COVERAGE_GRAPH_HH
+#define GRAPH_COVERAGE_GRAPH_HH
+
+namespace graph {
+
+struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
+ }
+};
+
+struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+ }
+};
+
+struct Coverage : public OT::Layout::Common::Coverage
+{
+ static Coverage* clone_coverage (gsubgpos_graph_context_t& c,
+ unsigned coverage_id,
+ unsigned new_parent_id,
+ unsigned link_position,
+ unsigned start, unsigned end)
+
+ {
+ unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table || !coverage_table->sanitize (coverage_v))
+ return nullptr;
+
+ auto new_coverage =
+ + hb_zip (coverage_table->iter (), hb_range ())
+ | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+ return p.second >= start && p.second < end;
+ })
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ return add_coverage (c, new_parent_id, link_position, new_coverage, coverage_size);
+ }
+
+ template<typename It>
+ static Coverage* add_coverage (gsubgpos_graph_context_t& c,
+ unsigned parent_id,
+ unsigned link_position,
+ It glyphs,
+ unsigned max_size)
+ {
+ unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
+ auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
+ if (!make_coverage (c, glyphs, coverage_prime_id, max_size))
+ return nullptr;
+
+ auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+ coverage_link->width = SmallTypes::size;
+ coverage_link->objidx = coverage_prime_id;
+ coverage_link->position = link_position;
+ coverage_prime_vertex.parents.push (parent_id);
+
+ return (Coverage*) coverage_prime_vertex.obj.head;
+ }
+
+ template<typename It>
+ static bool make_coverage (gsubgpos_graph_context_t& c,
+ It glyphs,
+ unsigned dest_obj,
+ unsigned max_size)
+ {
+ char* buffer = (char*) hb_calloc (1, max_size);
+ hb_serialize_context_t serializer (buffer, max_size);
+ OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ if (serializer.in_error ())
+ {
+ hb_free (buffer);
+ return false;
+ }
+
+ hb_bytes_t coverage_copy = serializer.copy_bytes ();
+ c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+ auto& obj = c.graph.vertices_[dest_obj].obj;
+ obj.head = (char *) coverage_copy.arrayZ;
+ obj.tail = obj.head + coverage_copy.length;
+
+ hb_free (buffer);
+ return true;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
+ switch (u.format)
+ {
+ case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
+ case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+ // Not currently supported
+ case 3:
+ case 4:
+#endif
+ default: return false;
+ }
+ }
+};
+
+
+}
+
+#endif // GRAPH_COVERAGE_GRAPH_HH
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
new file mode 100644
index 000000000..dc5b6a36f
--- /dev/null
+++ b/src/graph/graph.hh
@@ -0,0 +1,1385 @@
+/*
+ * 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
+ */
+
+#include "../hb-set.hh"
+#include "../hb-priority-queue.hh"
+#include "../hb-serialize.hh"
+
+#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;
+
+
+ bool link_positions_valid (unsigned num_objects, bool removed_nil)
+ {
+ hb_set_t assigned_bytes;
+ for (const auto& l : obj.real_links)
+ {
+ if (l.objidx >= num_objects
+ || (removed_nil && !l.objidx))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Invalid object index.");
+ return false;
+ }
+
+ unsigned start = l.position;
+ unsigned end = start + l.width - 1;
+
+ if (unlikely (l.width < 2 || l.width > 4))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Invalid link width.");
+ return false;
+ }
+
+ if (unlikely (end >= table_size ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Link position is out of bounds.");
+ return false;
+ }
+
+ if (unlikely (assigned_bytes.intersects (start, end)))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Invalid graph. Found offsets whose positions overlap.");
+ return false;
+ }
+
+ assigned_bytes.add_range (start, end);
+ }
+
+ return !assigned_bytes.in_error ();
+ }
+
+ void normalize ()
+ {
+ obj.real_links.qsort ();
+ for (auto& l : obj.real_links)
+ {
+ for (unsigned i = 0; i < l.width; i++)
+ {
+ obj.head[l.position + i] = 0;
+ }
+ }
+ }
+
+ bool equals (const vertex_t& other,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ if (!(as_bytes () == other.as_bytes ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "vertex [%lu] bytes != [%lu] bytes, depth = %u",
+ (unsigned long) table_size (),
+ (unsigned long) other.table_size (),
+ depth);
+
+ auto a = as_bytes ();
+ auto b = other.as_bytes ();
+ while (a || b)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b);
+ a++;
+ b++;
+ }
+ return false;
+ }
+
+ return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth);
+ }
+
+ hb_bytes_t as_bytes () const
+ {
+ return hb_bytes_t (obj.head, table_size ());
+ }
+
+ 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);
+ }
+
+ hb_hashmap_t<unsigned, unsigned>
+ position_to_index_map () const
+ {
+ hb_hashmap_t<unsigned, unsigned> result;
+
+ for (const auto& l : obj.real_links) {
+ result.set (l.position, l.objidx);
+ }
+
+ return result;
+ }
+
+ 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_unordered (i);
+ break;
+ }
+ }
+
+ void remove_real_link (unsigned child_index, const void* offset)
+ {
+ for (unsigned i = 0; i < obj.real_links.length; i++)
+ {
+ auto& link = obj.real_links.arrayZ[i];
+ if (link.objidx != child_index)
+ continue;
+
+ if ((obj.head + link.position) != offset)
+ continue;
+
+ obj.real_links.remove_unordered (i);
+ return;
+ }
+ }
+
+ 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;
+ }
+
+ size_t table_size () const {
+ return obj.tail - obj.head;
+ }
+
+ 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;
+ }
+
+ private:
+ bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links,
+ const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ auto a = this_links.iter ();
+ auto b = other_links.iter ();
+
+ while (a && b)
+ {
+ const auto& link_a = *a;
+ const auto& link_b = *b;
+
+ if (link_a.width != link_b.width ||
+ link_a.is_signed != link_b.is_signed ||
+ link_a.whence != link_b.whence ||
+ link_a.position != link_b.position ||
+ link_a.bias != link_b.bias)
+ return false;
+
+ if (!graph.vertices_[link_a.objidx].equals (
+ other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
+ return false;
+
+ a++;
+ b++;
+ }
+
+ if (bool (a) != bool (b))
+ return false;
+
+ return true;
+ }
+ };
+
+ template <typename T>
+ struct vertex_and_table_t
+ {
+ vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr)
+ {}
+
+ unsigned index;
+ vertex_t* vertex;
+ T* table;
+
+ operator bool () {
+ return table && vertex;
+ }
+ };
+
+ /*
+ * 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),
+ buffers ()
+ {
+ 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++)
+ {
+ // 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];
+
+ check_success (v->link_positions_valid (objects.length, removed_nil));
+
+ 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 ();
+ for (char* b : buffers)
+ hb_free (b);
+ }
+
+ bool operator== (const graph_t& other) const
+ {
+ return root ().equals (other.root (), *this, other, 0);
+ }
+
+ // Sorts links of all objects in a consistent manner and zeroes all offsets.
+ void normalize ()
+ {
+ for (auto& v : vertices_.writer ())
+ v.normalize ();
+ }
+
+ 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;
+ }
+
+ void add_buffer (char* buffer)
+ {
+ buffers.push (buffer);
+ }
+
+ /*
+ * Adds a 16 bit link from parent_id to child_id
+ */
+ template<typename T>
+ void add_link (T* offset,
+ unsigned parent_id,
+ unsigned child_id)
+ {
+ auto& v = vertices_[parent_id];
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = child_id;
+ link->position = (char*) offset - (char*) v.obj.head;
+ vertices_[child_id].parents.push (parent_id);
+ }
+
+ /*
+ * Generates a new topological sorting of graph ordered by the shortest
+ * distance to each node if positions are marked as invalid.
+ */
+ void sort_shortest_distance_if_needed ()
+ {
+ if (!positions_invalid) return;
+ sort_shortest_distance ();
+ }
+
+
+ /*
+ * 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];
+
+ if (unlikely (!check_success(new_id >= 0))) {
+ // We are out of ids. Which means we've visited a node more than once.
+ // This graph contains a cycle which is not allowed.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
+ return;
+ }
+
+ 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 ());
+
+ remap_all_obj_indices (id_map, &sorted_graph);
+ hb_swap (vertices_, sorted_graph);
+
+ if (!check_success (new_id == -1))
+ print_orphaned_nodes ();
+ }
+
+ /*
+ * Finds the set of nodes (placed into roots) that should be assigned unique spaces.
+ * More specifically this looks for the top most 24 bit or 32 bit links in the graph.
+ * Some special casing is done that is specific to the layout of GSUB/GPOS tables.
+ */
+ void find_space_roots (hb_set_t& visited, hb_set_t& roots)
+ {
+ int root_index = (int) root_idx ();
+ for (int i = root_index; i >= 0; i--)
+ {
+ if (visited.has (i)) continue;
+
+ // Only real links can form 32 bit spaces
+ for (auto& l : vertices_[i].obj.real_links)
+ {
+ if (l.is_signed || l.width < 3)
+ continue;
+
+ if (i == root_index && l.width == 3)
+ // Ignore 24bit links from the root node, this skips past the single 24bit
+ // pointer to the lookup list.
+ continue;
+
+ if (l.width == 3)
+ {
+ // A 24bit offset forms a root, unless there is 32bit offsets somewhere
+ // in it's subgraph, then those become the roots instead. This is to make sure
+ // that extension subtables beneath a 24bit lookup become the spaces instead
+ // of the offset to the lookup.
+ hb_set_t sub_roots;
+ find_32bit_roots (l.objidx, sub_roots);
+ if (sub_roots) {
+ for (unsigned sub_root_idx : sub_roots) {
+ roots.add (sub_root_idx);
+ find_subgraph (sub_root_idx, visited);
+ }
+ continue;
+ }
+ }
+
+ roots.add (l.objidx);
+ find_subgraph (l.objidx, visited);
+ }
+ }
+ }
+
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds)
+ {
+ return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+ }
+
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
+ {
+ return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+ }
+
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
+ {
+ if (index >= vertices_.length)
+ return vertex_and_table_t<T> ();
+
+ vertex_and_table_t<T> r;
+ r.vertex = &vertices_[index];
+ r.table = (T*) r.vertex->obj.head;
+ r.index = index;
+ if (!r.table)
+ return vertex_and_table_t<T> ();
+
+ if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...))
+ return vertex_and_table_t<T> ();
+
+ return r;
+ }
+
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx].
+ unsigned index_for_offset (unsigned node_idx, const void* offset) const
+ {
+ const auto& node = object (node_idx);
+ if (offset < node.head || offset >= node.tail) return -1;
+
+ unsigned length = node.real_links.length;
+ for (unsigned i = 0; i < length; i++)
+ {
+ // Use direct access for increased performance, this is a hot method.
+ const auto& link = node.real_links.arrayZ[i];
+ if (offset != node.head + link.position)
+ continue;
+ return link.objidx;
+ }
+
+ return -1;
+ }
+
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx]. Ensures that the returned object is safe to mutate.
+ // That is, if the original child object is shared by parents other than node_idx
+ // it will be duplicated and the duplicate will be returned instead.
+ unsigned mutable_index_for_offset (unsigned node_idx, const void* offset)
+ {
+ unsigned child_idx = index_for_offset (node_idx, offset);
+ auto& child = vertices_[child_idx];
+ for (unsigned p : child.parents)
+ {
+ if (p != node_idx) {
+ return duplicate (node_idx, child_idx);
+ }
+ }
+
+ return child_idx;
+ }
+
+
+ /*
+ * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
+ * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
+ * (including with 24bit offsets) table.
+ */
+ bool assign_spaces ()
+ {
+ update_parents ();
+
+ hb_set_t visited;
+ hb_set_t roots;
+ find_space_roots (visited, roots);
+
+ // Mark everything not in the subgraphs of the roots as visited. This prevents
+ // subgraphs from being connected via nodes not in those subgraphs.
+ visited.invert ();
+
+ if (!roots) return false;
+
+ while (roots)
+ {
+ uint32_t 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([&] (uint32_t node_idx) {
+ const uint32_t *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.
+ uint32_t next = HB_SET_VALUE_INVALID;
+ while (roots.next (&next))
+ {
+ const uint32_t *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 uint32_t *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);
+ }
+
+ size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
+ {
+ if (subgraph.has (node_idx)) return 0;
+ subgraph.add (node_idx);
+
+ const auto& o = vertices_[node_idx].obj;
+ size_t size = o.tail - o.head;
+ if (max_depth == 0)
+ return size;
+
+ for (const auto& link : o.all_links ())
+ size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
+ return size;
+ }
+
+ /*
+ * Finds the topmost children of 32bit offsets in the subgraph starting
+ * at node_idx. Found indices are placed into 'found'.
+ */
+ void find_32bit_roots (unsigned node_idx, hb_set_t& found)
+ {
+ for (const auto& link : vertices_[node_idx].obj.all_links ())
+ {
+ if (!link.is_signed && link.width == 4) {
+ found.add (link.objidx);
+ continue;
+ }
+ find_32bit_roots (link.objidx, found);
+ }
+ }
+
+ /*
+ * Moves the child of old_parent_idx pointed to by old_offset to a new
+ * vertex at the new_offset.
+ */
+ template<typename O>
+ void move_child (unsigned old_parent_idx,
+ const O* old_offset,
+ unsigned new_parent_idx,
+ const O* new_offset)
+ {
+ distance_invalid = true;
+ positions_invalid = true;
+
+ auto& old_v = vertices_[old_parent_idx];
+ auto& new_v = vertices_[new_parent_idx];
+
+ unsigned child_id = index_for_offset (old_parent_idx,
+ old_offset);
+
+ auto* new_link = new_v.obj.real_links.push ();
+ new_link->width = O::static_size;
+ new_link->objidx = child_id;
+ new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
+
+ auto& child = vertices_[child_id];
+ child.parents.push (new_parent_idx);
+
+ old_v.remove_real_link (child_id, old_offset);
+ child.remove_parent (old_parent_idx);
+ }
+
+ /*
+ * 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.
+ */
+ unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
+ {
+ unsigned new_idx = duplicate (parent_idx, child_idx);
+ if (new_idx == (unsigned) -1) return child_idx;
+ return new_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.
+ */
+ unsigned 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 -1;
+ }
+
+ 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 clone_idx;
+ }
+
+
+ /*
+ * Adds a new node to the graph, not connected to anything.
+ */
+ unsigned new_node (char* head, char* tail)
+ {
+ positions_invalid = true;
+ distance_invalid = true;
+
+ auto* clone = vertices_.push ();
+ if (vertices_.in_error ()) {
+ return -1;
+ }
+
+ clone->obj.head = head;
+ clone->obj.tail = tail;
+ clone->distance = 0;
+ clone->space = 0;
+
+ unsigned clone_idx = vertices_.length - 2;
+
+ // 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;
+ }
+
+ /*
+ * 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;
+ }
+
+ bool is_fully_connected ()
+ {
+ update_parents();
+
+ if (root().parents)
+ // Root cannot have parents.
+ return false;
+
+ for (unsigned i = 0; i < root_idx (); i++)
+ {
+ if (!vertices_[i].parents)
+ return false;
+ }
+ return true;
+ }
+
+#if 0
+ /*
+ * Saves the current graph to a packed binary format which the repacker fuzzer takes
+ * as a seed.
+ */
+ void save_fuzzer_seed (hb_tag_t tag) const
+ {
+ FILE* f = fopen ("./repacker_fuzzer_seed", "w");
+ fwrite ((void*) &tag, sizeof (tag), 1, f);
+
+ uint16_t num_objects = vertices_.length;
+ fwrite ((void*) &num_objects, sizeof (num_objects), 1, f);
+
+ for (const auto& v : vertices_)
+ {
+ uint16_t blob_size = v.table_size ();
+ fwrite ((void*) &blob_size, sizeof (blob_size), 1, f);
+ fwrite ((const void*) v.obj.head, blob_size, 1, f);
+ }
+
+ uint16_t link_count = 0;
+ for (const auto& v : vertices_)
+ link_count += v.obj.real_links.length;
+
+ fwrite ((void*) &link_count, sizeof (link_count), 1, f);
+
+ typedef struct
+ {
+ uint16_t parent;
+ uint16_t child;
+ uint16_t position;
+ uint8_t width;
+ } link_t;
+
+ for (unsigned i = 0; i < vertices_.length; i++)
+ {
+ for (const auto& l : vertices_[i].obj.real_links)
+ {
+ link_t link {
+ (uint16_t) i, (uint16_t) l.objidx,
+ (uint16_t) l.position, (uint8_t) l.width
+ };
+ fwrite ((void*) &link, sizeof (link), 1, f);
+ }
+ }
+
+ fclose (f);
+ }
+#endif
+
+ 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();
+
+ if (root().parents) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
+ }
+
+ 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 24 or 32 bits 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 == 3 || 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);
+ }
+ }
+
+ for (unsigned i = 0; i < vertices_.length; i++)
+ // parents arrays must be accurate or downstream operations like cycle detection
+ // and sorting won't work correctly.
+ check_success (!vertices_[i].parents.in_error ());
+
+ 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 uint32_t *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_;
+ hb_vector_t<char*> buffers;
+};
+
+}
+
+#endif // GRAPH_GRAPH_HH
diff --git a/src/graph/gsubgpos-context.cc b/src/graph/gsubgpos-context.cc
new file mode 100644
index 000000000..b2044426d
--- /dev/null
+++ b/src/graph/gsubgpos-context.cc
@@ -0,0 +1,70 @@
+/*
+ * 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
+ */
+
+#include "gsubgpos-graph.hh"
+
+namespace graph {
+
+gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
+ graph_t& graph_)
+ : table_tag (table_tag_),
+ graph (graph_),
+ lookup_list_index (0),
+ lookups ()
+{
+ if (table_tag_ != HB_OT_TAG_GPOS
+ && table_tag_ != HB_OT_TAG_GSUB)
+ return;
+
+ GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_);
+ if (gstar) {
+ gstar->find_lookups (graph, lookups);
+ lookup_list_index = gstar->get_lookup_list_index (graph_);
+ }
+}
+
+unsigned gsubgpos_graph_context_t::create_node (unsigned size)
+{
+ char* buffer = (char*) hb_calloc (1, size);
+ if (!buffer)
+ return -1;
+
+ add_buffer (buffer);
+
+ return graph.new_node (buffer, buffer + size);
+}
+
+unsigned gsubgpos_graph_context_t::num_non_ext_subtables () {
+ unsigned count = 0;
+ for (auto l : lookups.values ())
+ {
+ if (l->is_extension (table_tag)) continue;
+ count += l->number_of_subtables ();
+ }
+ return count;
+}
+
+}
diff --git a/src/graph/gsubgpos-context.hh b/src/graph/gsubgpos-context.hh
new file mode 100644
index 000000000..9fe9662e6
--- /dev/null
+++ b/src/graph/gsubgpos-context.hh
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+
+#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
+#define GRAPH_GSUBGPOS_CONTEXT_HH
+
+namespace graph {
+
+struct Lookup;
+
+struct gsubgpos_graph_context_t
+{
+ hb_tag_t table_tag;
+ graph_t& graph;
+ unsigned lookup_list_index;
+ hb_hashmap_t<unsigned, graph::Lookup*> lookups;
+
+
+ HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
+ graph_t& graph_);
+
+ HB_INTERNAL unsigned create_node (unsigned size);
+
+ void add_buffer (char* buffer)
+ {
+ graph.add_buffer (buffer);
+ }
+
+ private:
+ HB_INTERNAL unsigned num_non_ext_subtables ();
+};
+
+}
+
+#endif // GRAPH_GSUBGPOS_CONTEXT
diff --git a/src/graph/gsubgpos-graph.hh b/src/graph/gsubgpos-graph.hh
new file mode 100644
index 000000000..c17063840
--- /dev/null
+++ b/src/graph/gsubgpos-graph.hh
@@ -0,0 +1,414 @@
+/*
+ * 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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+#include "../OT/Layout/GSUB/ExtensionSubst.hh"
+#include "gsubgpos-context.hh"
+#include "pairpos-graph.hh"
+#include "markbasepos-graph.hh"
+
+#ifndef GRAPH_GSUBGPOS_GRAPH_HH
+#define GRAPH_GSUBGPOS_GRAPH_HH
+
+namespace graph {
+
+struct Lookup;
+
+template<typename T>
+struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
+{
+ void reset(unsigned type)
+ {
+ this->format = 1;
+ this->extensionLookupType = type;
+ this->extensionOffset = 0;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ return vertex_len >= OT::ExtensionFormat1<T>::static_size;
+ }
+
+ unsigned get_lookup_type () const
+ {
+ return this->extensionLookupType;
+ }
+
+ unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
+ {
+ return graph.index_for_offset (this_index, &this->extensionOffset);
+ }
+};
+
+struct Lookup : public OT::Lookup
+{
+ unsigned number_of_subtables () const
+ {
+ return subTable.len;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::Lookup::min_size) return false;
+ return vertex_len >= this->get_size ();
+ }
+
+ bool is_extension (hb_tag_t table_tag) const
+ {
+ return lookupType == extension_type (table_tag);
+ }
+
+ bool make_extension (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ unsigned type = lookupType;
+ unsigned ext_type = extension_type (c.table_tag);
+ if (!ext_type || is_extension (c.table_tag))
+ {
+ // NOOP
+ return true;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Promoting lookup type %u (obj %u) to extension.",
+ type,
+ this_index);
+
+ for (unsigned i = 0; i < subTable.len; i++)
+ {
+ unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+ if (!make_subtable_extension (c,
+ this_index,
+ subtable_index))
+ return false;
+ }
+
+ lookupType = ext_type;
+ return true;
+ }
+
+ bool split_subtables_if_needed (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ unsigned type = lookupType;
+ bool is_ext = is_extension (c.table_tag);
+
+ if (c.table_tag != HB_OT_TAG_GPOS)
+ return true;
+
+ if (!is_ext &&
+ type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair &&
+ type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+ return true;
+
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables;
+ for (unsigned i = 0; i < subTable.len; i++)
+ {
+ unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+ unsigned parent_index = this_index;
+ if (is_ext) {
+ unsigned ext_subtable_index = subtable_index;
+ parent_index = ext_subtable_index;
+ ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+ (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
+ c.graph.object (ext_subtable_index).head;
+ if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index]))
+ continue;
+
+ subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
+ type = extension->get_lookup_type ();
+ if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair
+ && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+ continue;
+ }
+
+ hb_vector_t<unsigned> new_sub_tables;
+ switch (type)
+ {
+ case 2:
+ new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
+ case 4:
+ new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
+ default:
+ break;
+ }
+ if (new_sub_tables.in_error ()) return false;
+ if (!new_sub_tables) continue;
+ hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push ();
+ entry->first = i;
+ entry->second = std::move (new_sub_tables);
+ }
+
+ if (all_new_subtables) {
+ add_sub_tables (c, this_index, type, all_new_subtables);
+ }
+
+ return true;
+ }
+
+ template<typename T>
+ hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
+ unsigned parent_idx,
+ unsigned objidx)
+ {
+ T* sub_table = (T*) c.graph.object (objidx).head;
+ if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
+ return hb_vector_t<unsigned> ();
+
+ return sub_table->split_subtables (c, parent_idx, objidx);
+ }
+
+ void add_sub_tables (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned type,
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
+ {
+ bool is_ext = is_extension (c.table_tag);
+ auto& v = c.graph.vertices_[this_index];
+ fix_existing_subtable_links (c, this_index, subtable_ids);
+
+ unsigned new_subtable_count = 0;
+ for (const auto& p : subtable_ids)
+ new_subtable_count += p.second.length;
+
+ size_t new_size = v.table_size ()
+ + new_subtable_count * OT::Offset16::static_size;
+ char* buffer = (char*) hb_calloc (1, new_size);
+ c.add_buffer (buffer);
+ hb_memcpy (buffer, v.obj.head, v.table_size());
+
+ v.obj.head = buffer;
+ v.obj.tail = buffer + new_size;
+
+ Lookup* new_lookup = (Lookup*) buffer;
+
+ unsigned shift = 0;
+ new_lookup->subTable.len = subTable.len + new_subtable_count;
+ for (const auto& p : subtable_ids)
+ {
+ unsigned offset_index = p.first + shift + 1;
+ shift += p.second.length;
+
+ for (unsigned subtable_id : p.second)
+ {
+ if (is_ext)
+ {
+ unsigned ext_id = create_extension_subtable (c, subtable_id, type);
+ c.graph.vertices_[subtable_id].parents.push (ext_id);
+ subtable_id = ext_id;
+ }
+
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = subtable_id;
+ link->position = (char*) &new_lookup->subTable[offset_index++] -
+ (char*) new_lookup;
+ c.graph.vertices_[subtable_id].parents.push (this_index);
+ }
+ }
+
+ // Repacker sort order depends on link order, which we've messed up so resort it.
+ v.obj.real_links.qsort ();
+
+ // The head location of the lookup has changed, invalidating the lookups map entry
+ // in the context. Update the map.
+ c.lookups.set (this_index, new_lookup);
+ }
+
+ void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
+ {
+ auto& v = c.graph.vertices_[this_index];
+ Lookup* lookup = (Lookup*) v.obj.head;
+
+ unsigned shift = 0;
+ for (const auto& p : subtable_ids)
+ {
+ unsigned insert_index = p.first + shift;
+ unsigned pos_offset = p.second.length * OT::Offset16::static_size;
+ unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup;
+ shift += p.second.length;
+
+ for (auto& l : v.obj.all_links_writer ())
+ {
+ if (l.position > insert_offset) l.position += pos_offset;
+ }
+ }
+ }
+
+ unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
+ unsigned subtable_index,
+ unsigned type)
+ {
+ unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
+
+ unsigned ext_index = c.create_node (extension_size);
+ if (ext_index == (unsigned) -1)
+ return -1;
+
+ auto& ext_vertex = c.graph.vertices_[ext_index];
+ ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+ (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
+ extension->reset (type);
+
+ // Make extension point at the subtable.
+ auto* l = ext_vertex.obj.real_links.push ();
+
+ l->width = 4;
+ l->objidx = subtable_index;
+ l->position = 4;
+
+ return ext_index;
+ }
+
+ bool make_subtable_extension (gsubgpos_graph_context_t& c,
+ unsigned lookup_index,
+ unsigned subtable_index)
+ {
+ unsigned type = lookupType;
+
+ unsigned ext_index = create_extension_subtable(c, subtable_index, type);
+ if (ext_index == (unsigned) -1)
+ return false;
+
+ auto& lookup_vertex = c.graph.vertices_[lookup_index];
+ for (auto& l : lookup_vertex.obj.real_links.writer ())
+ {
+ if (l.objidx == subtable_index)
+ // Change lookup to point at the extension.
+ l.objidx = ext_index;
+ }
+
+ // Make extension point at the subtable.
+ auto& ext_vertex = c.graph.vertices_[ext_index];
+ auto& subtable_vertex = c.graph.vertices_[subtable_index];
+ ext_vertex.parents.push (lookup_index);
+ subtable_vertex.remap_parent (lookup_index, ext_index);
+
+ return true;
+ }
+
+ private:
+ unsigned extension_type (hb_tag_t table_tag) const
+ {
+ switch (table_tag)
+ {
+ case HB_OT_TAG_GPOS: return 9;
+ case HB_OT_TAG_GSUB: return 7;
+ default: return 0;
+ }
+ }
+};
+
+template <typename T>
+struct LookupList : public OT::LookupList<T>
+{
+ bool sanitize (const graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::LookupList<T>::min_size) return false;
+ return vertex_len >= OT::LookupList<T>::item_size * this->len;
+ }
+};
+
+struct GSTAR : public OT::GSUBGPOS
+{
+ static GSTAR* graph_to_gstar (graph_t& graph)
+ {
+ const auto& r = graph.root ();
+
+ GSTAR* gstar = (GSTAR*) r.obj.head;
+ if (!gstar || !gstar->sanitize (r))
+ return nullptr;
+
+ return gstar;
+ }
+
+ const void* get_lookup_list_field_offset () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.get_lookup_list_offset ();
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.get_lookup_list_offset ();
+#endif
+ default: return 0;
+ }
+ }
+
+ bool sanitize (const graph_t::vertex_t& vertex)
+ {
+ int64_t len = vertex.obj.tail - vertex.obj.head;
+ if (len < OT::GSUBGPOS::min_size) return false;
+ return len >= get_size ();
+ }
+
+ void find_lookups (graph_t& graph,
+ hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+ {
+ switch (u.version.major) {
+ case 1: find_lookups<SmallTypes> (graph, lookups); break;
+#ifndef HB_NO_BEYOND_64K
+ case 2: find_lookups<MediumTypes> (graph, lookups); break;
+#endif
+ }
+ }
+
+ unsigned get_lookup_list_index (graph_t& graph)
+ {
+ return graph.index_for_offset (graph.root_idx (),
+ get_lookup_list_field_offset());
+ }
+
+ template<typename Types>
+ void find_lookups (graph_t& graph,
+ hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+ {
+ unsigned lookup_list_idx = get_lookup_list_index (graph);
+ const LookupList<Types>* lookupList =
+ (const LookupList<Types>*) graph.object (lookup_list_idx).head;
+ if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx]))
+ return;
+
+ for (unsigned i = 0; i < lookupList->len; i++)
+ {
+ unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
+ Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
+ if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue;
+ lookups.set (lookup_idx, lookup);
+ }
+ }
+};
+
+
+
+
+}
+
+#endif /* GRAPH_GSUBGPOS_GRAPH_HH */
diff --git a/src/graph/markbasepos-graph.hh b/src/graph/markbasepos-graph.hh
new file mode 100644
index 000000000..84ef5f71b
--- /dev/null
+++ b/src/graph/markbasepos-graph.hh
@@ -0,0 +1,510 @@
+/*
+ * 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_MARKBASEPOS_GRAPH_HH
+#define GRAPH_MARKBASEPOS_GRAPH_HH
+
+#include "split-helpers.hh"
+#include "coverage-graph.hh"
+#include "../OT/Layout/GPOS/MarkBasePos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
+{
+ bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < AnchorMatrix::min_size) return false;
+
+ return vertex_len >= AnchorMatrix::min_size +
+ OT::Offset16::static_size * class_count * this->rows;
+ }
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned old_class_count,
+ unsigned new_class_count)
+ {
+ if (new_class_count >= old_class_count) return false;
+ auto& o = c.graph.vertices_[this_index].obj;
+ unsigned base_count = rows;
+ o.tail = o.head +
+ AnchorMatrix::min_size +
+ OT::Offset16::static_size * base_count * new_class_count;
+
+ // Reposition links into the new indexing scheme.
+ for (auto& link : o.real_links.writer ())
+ {
+ unsigned index = (link.position - 2) / 2;
+ unsigned base = index / old_class_count;
+ unsigned klass = index % old_class_count;
+ if (klass >= new_class_count)
+ // should have already been removed
+ return false;
+
+ unsigned new_index = base * new_class_count + klass;
+
+ link.position = (char*) &(this->matrixZ[new_index]) - (char*) this;
+ }
+
+ return true;
+ }
+
+ unsigned clone (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned start,
+ unsigned end,
+ unsigned class_count)
+ {
+ unsigned base_count = rows;
+ unsigned new_class_count = end - start;
+ unsigned size = AnchorMatrix::min_size +
+ OT::Offset16::static_size * new_class_count * rows;
+ unsigned prime_id = c.create_node (size);
+ if (prime_id == (unsigned) -1) return -1;
+ AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head;
+ prime->rows = base_count;
+
+ auto& o = c.graph.vertices_[this_index].obj;
+ int num_links = o.real_links.length;
+ for (int i = 0; i < num_links; i++)
+ {
+ const auto& link = o.real_links[i];
+ unsigned old_index = (link.position - 2) / OT::Offset16::static_size;
+ unsigned klass = old_index % class_count;
+ if (klass < start || klass >= end) continue;
+
+ unsigned base = old_index / class_count;
+ unsigned new_klass = klass - start;
+ unsigned new_index = base * new_class_count + new_klass;
+
+
+ unsigned child_idx = link.objidx;
+ c.graph.add_link (&(prime->matrixZ[new_index]),
+ prime_id,
+ child_idx);
+
+ auto& child = c.graph.vertices_[child_idx];
+ child.remove_parent (this_index);
+
+ o.real_links.remove_unordered (i);
+ num_links--;
+ i--;
+ }
+
+ return prime_id;
+ }
+};
+
+struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ unsigned min_size = MarkArray::min_size;
+ if (vertex_len < min_size) return false;
+
+ return vertex_len >= get_size ();
+ }
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ const hb_hashmap_t<unsigned, unsigned>& mark_array_links,
+ unsigned this_index,
+ unsigned new_class_count)
+ {
+ auto& o = c.graph.vertices_[this_index].obj;
+ for (const auto& link : o.real_links)
+ c.graph.vertices_[link.objidx].remove_parent (this_index);
+ o.real_links.reset ();
+
+ unsigned new_index = 0;
+ for (const auto& record : this->iter ())
+ {
+ unsigned klass = record.klass;
+ if (klass >= new_class_count) continue;
+
+ (*this)[new_index].klass = klass;
+ unsigned position = (char*) &record.markAnchor - (char*) this;
+ unsigned* objidx;
+ if (!mark_array_links.has (position, &objidx))
+ {
+ new_index++;
+ continue;
+ }
+
+ c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx);
+ new_index++;
+ }
+
+ this->len = new_index;
+ o.tail = o.head + MarkArray::min_size +
+ OT::Layout::GPOS_impl::MarkRecord::static_size * new_index;
+ return true;
+ }
+
+ unsigned clone (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ const hb_hashmap_t<unsigned, unsigned>& pos_to_index,
+ hb_set_t& marks,
+ unsigned start_class)
+ {
+ unsigned size = MarkArray::min_size +
+ OT::Layout::GPOS_impl::MarkRecord::static_size *
+ marks.get_population ();
+ unsigned prime_id = c.create_node (size);
+ if (prime_id == (unsigned) -1) return -1;
+ MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head;
+ prime->len = marks.get_population ();
+
+
+ unsigned i = 0;
+ for (hb_codepoint_t mark : marks)
+ {
+ (*prime)[i].klass = (*this)[mark].klass - start_class;
+ unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this;
+ unsigned* anchor_index;
+ if (pos_to_index.has (offset_pos, &anchor_index))
+ c.graph.move_child (this_index,
+ &((*this)[mark].markAnchor),
+ prime_id,
+ &((*prime)[i].markAnchor));
+
+ i++;
+ }
+
+ return prime_id;
+ }
+};
+
+struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ return vertex_len >= MarkBasePosFormat1::static_size;
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
+ {
+ hb_set_t visited;
+
+ const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage);
+ const unsigned base_size =
+ OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size +
+ MarkArray::min_size +
+ AnchorMatrix::min_size +
+ c.graph.vertices_[base_coverage_id].table_size ();
+
+ hb_vector_t<class_info_t> class_to_info = get_class_info (c, this_index);
+
+ unsigned class_count = classCount;
+ auto base_array = c.graph.as_table<AnchorMatrix> (this_index,
+ &baseArray,
+ class_count);
+ if (!base_array) return hb_vector_t<unsigned> ();
+ unsigned base_count = base_array.table->rows;
+
+ unsigned partial_coverage_size = 4;
+ unsigned accumulated = base_size;
+ hb_vector_t<unsigned> split_points;
+
+ for (unsigned klass = 0; klass < class_count; klass++)
+ {
+ class_info_t& info = class_to_info[klass];
+ partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population ();
+ unsigned accumulated_delta =
+ OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () +
+ OT::Offset16::static_size * base_count;
+
+ for (unsigned objidx : info.child_indices)
+ accumulated_delta += c.graph.find_subgraph_size (objidx, visited);
+
+ accumulated += accumulated_delta;
+ unsigned total = accumulated + partial_coverage_size;
+
+ if (total >= (1 << 16))
+ {
+ split_points.push (klass);
+ accumulated = base_size + accumulated_delta;
+ partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population ();
+ visited.clear (); // node sharing isn't allowed between splits.
+ }
+ }
+
+
+ const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray);
+ split_context_t split_context {
+ c,
+ this,
+ c.graph.duplicate_if_shared (parent_index, this_index),
+ std::move (class_to_info),
+ c.graph.vertices_[mark_array_id].position_to_index_map (),
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
+ }
+
+ private:
+
+ struct class_info_t {
+ hb_set_t marks;
+ hb_vector_t<unsigned> child_indices;
+ };
+
+ struct split_context_t {
+ gsubgpos_graph_context_t& c;
+ MarkBasePosFormat1* thiz;
+ unsigned this_index;
+ hb_vector_t<class_info_t> class_to_info;
+ hb_hashmap_t<unsigned, unsigned> mark_array_links;
+
+ hb_set_t marks_for (unsigned start, unsigned end)
+ {
+ hb_set_t marks;
+ for (unsigned klass = start; klass < end; klass++)
+ {
+ + class_to_info[klass].marks.iter ()
+ | hb_sink (marks)
+ ;
+ }
+ return marks;
+ }
+
+ unsigned original_count ()
+ {
+ return thiz->classCount;
+ }
+
+ unsigned clone_range (unsigned start, unsigned end)
+ {
+ return thiz->clone_range (*this, this->this_index, start, end);
+ }
+
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (*this, this->this_index, count);
+ }
+ };
+
+ hb_vector_t<class_info_t> get_class_info (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ hb_vector_t<class_info_t> class_to_info;
+
+ unsigned class_count= classCount;
+ class_to_info.resize (class_count);
+
+ auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray);
+ if (!mark_array) return hb_vector_t<class_info_t> ();
+ unsigned mark_count = mark_array.table->len;
+ for (unsigned mark = 0; mark < mark_count; mark++)
+ {
+ unsigned klass = (*mark_array.table)[mark].get_class ();
+ class_to_info[klass].marks.add (mark);
+ }
+
+ for (const auto& link : mark_array.vertex->obj.real_links)
+ {
+ unsigned mark = (link.position - 2) /
+ OT::Layout::GPOS_impl::MarkRecord::static_size;
+ unsigned klass = (*mark_array.table)[mark].get_class ();
+ class_to_info[klass].child_indices.push (link.objidx);
+ }
+
+ unsigned base_array_id =
+ c.graph.index_for_offset (this_index, &baseArray);
+ auto& base_array_v = c.graph.vertices_[base_array_id];
+
+ for (const auto& link : base_array_v.obj.real_links)
+ {
+ unsigned index = (link.position - 2) / OT::Offset16::static_size;
+ unsigned klass = index % class_count;
+ class_to_info[klass].child_indices.push (link.objidx);
+ }
+
+ return class_to_info;
+ }
+
+ bool shrink (split_context_t& sc,
+ unsigned this_index,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking MarkBasePosFormat1 (%u) to [0, %u).",
+ this_index,
+ count);
+
+ unsigned old_count = classCount;
+ if (count >= old_count)
+ return true;
+
+ classCount = count;
+
+ auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
+ &markCoverage);
+ if (!mark_coverage) return false;
+ hb_set_t marks = sc.marks_for (0, count);
+ auto new_coverage =
+ + hb_enumerate (mark_coverage.table->iter ())
+ | hb_filter (marks, hb_first)
+ | hb_map_retains_sorting (hb_second)
+ ;
+ if (!Coverage::make_coverage (sc.c, + new_coverage,
+ mark_coverage.index,
+ 4 + 2 * marks.get_population ()))
+ return false;
+
+
+ auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index,
+ &baseArray,
+ old_count);
+ if (!base_array || !base_array.table->shrink (sc.c,
+ base_array.index,
+ old_count,
+ count))
+ return false;
+
+ auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
+ &markArray);
+ if (!mark_array || !mark_array.table->shrink (sc.c,
+ sc.mark_array_links,
+ mark_array.index,
+ count))
+ return false;
+
+ return true;
+ }
+
+ // Create a new MarkBasePos that has all of the data for classes from [start, end).
+ unsigned clone_range (split_context_t& sc,
+ unsigned this_index,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+ graph_t& graph = sc.c.graph;
+ unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::static_size;
+
+ unsigned prime_id = sc.c.create_node (prime_size);
+ if (prime_id == (unsigned) -1) return -1;
+
+ MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head;
+ prime->format = this->format;
+ unsigned new_class_count = end - start;
+ prime->classCount = new_class_count;
+
+ unsigned base_coverage_id =
+ graph.index_for_offset (sc.this_index, &baseCoverage);
+ graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id);
+ graph.duplicate (prime_id, base_coverage_id);
+
+ auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
+ &markCoverage);
+ if (!mark_coverage) return false;
+ hb_set_t marks = sc.marks_for (start, end);
+ auto new_coverage =
+ + hb_enumerate (mark_coverage.table->iter ())
+ | hb_filter (marks, hb_first)
+ | hb_map_retains_sorting (hb_second)
+ ;
+ if (!Coverage::add_coverage (sc.c,
+ prime_id,
+ 2,
+ + new_coverage,
+ marks.get_population () * 2 + 4))
+ return -1;
+
+ auto mark_array =
+ graph.as_table <MarkArray> (sc.this_index, &markArray);
+ if (!mark_array) return -1;
+ unsigned new_mark_array =
+ mark_array.table->clone (sc.c,
+ mark_array.index,
+ sc.mark_array_links,
+ marks,
+ start);
+ graph.add_link (&(prime->markArray), prime_id, new_mark_array);
+
+ unsigned class_count = classCount;
+ auto base_array =
+ graph.as_table<AnchorMatrix> (sc.this_index, &baseArray, class_count);
+ if (!base_array) return -1;
+ unsigned new_base_array =
+ base_array.table->clone (sc.c,
+ base_array.index,
+ start, end, this->classCount);
+ graph.add_link (&(prime->baseArray), prime_id, new_base_array);
+
+ return prime_id;
+ }
+};
+
+
+struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
+{
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
+ {
+ switch (u.format) {
+ case 1:
+ return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+#ifndef HB_NO_BEYOND_64K
+ case 2: HB_FALLTHROUGH;
+ // Don't split 24bit PairPos's.
+#endif
+ default:
+ return hb_vector_t<unsigned> ();
+ }
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < u.format.get_size ()) return false;
+
+ switch (u.format) {
+ case 1:
+ return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+ case 2: HB_FALLTHROUGH;
+#endif
+ default:
+ // We don't handle format 3 and 4 here.
+ return false;
+ }
+ }
+};
+
+
+}
+
+#endif // GRAPH_MARKBASEPOS_GRAPH_HH
diff --git a/src/graph/pairpos-graph.hh b/src/graph/pairpos-graph.hh
new file mode 100644
index 000000000..1c13eb24f
--- /dev/null
+++ b/src/graph/pairpos-graph.hh
@@ -0,0 +1,647 @@
+/*
+ * 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_PAIRPOS_GRAPH_HH
+#define GRAPH_PAIRPOS_GRAPH_HH
+
+#include "split-helpers.hh"
+#include "coverage-graph.hh"
+#include "classdef-graph.hh"
+#include "../OT/Layout/GPOS/PairPos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+
+ return vertex_len >=
+ min_size + pairSet.get_size () - pairSet.len.get_size();
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
+ {
+ hb_set_t visited;
+
+ const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+
+ unsigned partial_coverage_size = 4;
+ unsigned accumulated = base_size;
+ hb_vector_t<unsigned> split_points;
+ for (unsigned i = 0; i < pairSet.len; i++)
+ {
+ unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
+ unsigned accumulated_delta =
+ c.graph.find_subgraph_size (pair_set_index, visited) +
+ SmallTypes::size; // for PairSet offset.
+ partial_coverage_size += OT::HBUINT16::static_size;
+
+ accumulated += accumulated_delta;
+ unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size);
+
+ if (total >= (1 << 16))
+ {
+ split_points.push (i);
+ accumulated = base_size + accumulated_delta;
+ partial_coverage_size = 6;
+ visited.clear (); // node sharing isn't allowed between splits.
+ }
+ }
+
+ split_context_t split_context {
+ c,
+ this,
+ c.graph.duplicate_if_shared (parent_index, this_index),
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
+ }
+
+ private:
+
+ struct split_context_t {
+ gsubgpos_graph_context_t& c;
+ PairPosFormat1* thiz;
+ unsigned this_index;
+
+ unsigned original_count ()
+ {
+ return thiz->pairSet.len;
+ }
+
+ unsigned clone_range (unsigned start, unsigned end)
+ {
+ return thiz->clone_range (this->c, this->this_index, start, end);
+ }
+
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (this->c, this->this_index, count);
+ }
+ };
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking PairPosFormat1 (%u) to [0, %u).",
+ this_index,
+ count);
+ unsigned old_count = pairSet.len;
+ if (count >= old_count)
+ return true;
+
+ pairSet.len = count;
+ c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
+
+ auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
+ if (!coverage) return false;
+
+ unsigned coverage_size = coverage.vertex->table_size ();
+ auto new_coverage =
+ + hb_zip (coverage.table->iter (), hb_range ())
+ | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+ return p.second < count;
+ })
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
+ }
+
+ // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
+ // Returns object id of the new object.
+ unsigned clone_range (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+ unsigned num_pair_sets = end - start;
+ unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+ + num_pair_sets * SmallTypes::size;
+
+ unsigned pair_pos_prime_id = c.create_node (prime_size);
+ if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+ PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
+ pair_pos_prime->format = this->format;
+ pair_pos_prime->valueFormat[0] = this->valueFormat[0];
+ pair_pos_prime->valueFormat[1] = this->valueFormat[1];
+ pair_pos_prime->pairSet.len = num_pair_sets;
+
+ for (unsigned i = start; i < end; i++)
+ {
+ c.graph.move_child<> (this_index,
+ &pairSet[i],
+ pair_pos_prime_id,
+ &pair_pos_prime->pairSet[i - start]);
+ }
+
+ unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ if (!Coverage::clone_coverage (c,
+ coverage_id,
+ pair_pos_prime_id,
+ 2,
+ start, end))
+ return -1;
+
+ return pair_pos_prime_id;
+ }
+
+
+
+ unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+ {
+ return c.graph.index_for_offset (this_index, &pairSet[i]);
+ }
+};
+
+struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ size_t vertex_len = vertex.table_size ();
+ unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+
+ const unsigned class1_count = class1Count;
+ return vertex_len >=
+ min_size + class1_count * get_class1_record_size ();
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
+ {
+ const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+ const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
+ const Coverage* coverage = get_coverage (c, this_index);
+ const ClassDef* class_def_1 = get_class_def_1 (c, this_index);
+ auto gid_and_class =
+ + coverage->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid));
+ })
+ ;
+ class_def_size_estimator_t estimator (gid_and_class);
+
+ const unsigned class1_count = class1Count;
+ const unsigned class2_count = class2Count;
+ const unsigned class1_record_size = get_class1_record_size ();
+
+ const unsigned value_1_len = valueFormat1.get_len ();
+ const unsigned value_2_len = valueFormat2.get_len ();
+ const unsigned total_value_len = value_1_len + value_2_len;
+
+ unsigned accumulated = base_size;
+ unsigned coverage_size = 4;
+ unsigned class_def_1_size = 4;
+ unsigned max_coverage_size = coverage_size;
+ unsigned max_class_def_1_size = class_def_1_size;
+
+ hb_vector_t<unsigned> split_points;
+
+ hb_hashmap_t<unsigned, unsigned> device_tables = get_all_device_tables (c, this_index);
+ hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices ();
+ hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices ();
+ bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices);
+
+ hb_set_t visited;
+ for (unsigned i = 0; i < class1_count; i++)
+ {
+ unsigned accumulated_delta = class1_record_size;
+ coverage_size += estimator.incremental_coverage_size (i);
+ class_def_1_size += estimator.incremental_class_def_size (i);
+ max_coverage_size = hb_max (max_coverage_size, coverage_size);
+ max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
+
+ if (has_device_tables) {
+ for (unsigned j = 0; j < class2_count; j++)
+ {
+ unsigned value1_index = total_value_len * (class2_count * i + j);
+ unsigned value2_index = value1_index + value_1_len;
+ accumulated_delta += size_of_value_record_children (c,
+ device_tables,
+ format1_device_table_indices,
+ value1_index,
+ visited);
+ accumulated_delta += size_of_value_record_children (c,
+ device_tables,
+ format2_device_table_indices,
+ value2_index,
+ visited);
+ }
+ }
+
+ accumulated += accumulated_delta;
+ unsigned total = accumulated
+ + coverage_size + class_def_1_size + class_def_2_size
+ // The largest object will pack last and can exceed the size limit.
+ - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size);
+ if (total >= (1 << 16))
+ {
+ split_points.push (i);
+ // split does not include i, so add the size for i when we reset the size counters.
+ accumulated = base_size + accumulated_delta;
+ coverage_size = 4 + estimator.incremental_coverage_size (i);
+ class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+ visited.clear (); // node sharing isn't allowed between splits.
+ }
+ }
+
+ split_context_t split_context {
+ c,
+ this,
+ c.graph.duplicate_if_shared (parent_index, this_index),
+ class1_record_size,
+ total_value_len,
+ value_1_len,
+ value_2_len,
+ max_coverage_size,
+ max_class_def_1_size,
+ device_tables,
+ format1_device_table_indices,
+ format2_device_table_indices
+ };
+
+ return actuate_subtable_split<split_context_t> (split_context, split_points);
+ }
+ private:
+
+ struct split_context_t
+ {
+ gsubgpos_graph_context_t& c;
+ PairPosFormat2* thiz;
+ unsigned this_index;
+ unsigned class1_record_size;
+ unsigned value_record_len;
+ unsigned value1_record_len;
+ unsigned value2_record_len;
+ unsigned max_coverage_size;
+ unsigned max_class_def_size;
+
+ const hb_hashmap_t<unsigned, unsigned>& device_tables;
+ const hb_vector_t<unsigned>& format1_device_table_indices;
+ const hb_vector_t<unsigned>& format2_device_table_indices;
+
+ unsigned original_count ()
+ {
+ return thiz->class1Count;
+ }
+
+ unsigned clone_range (unsigned start, unsigned end)
+ {
+ return thiz->clone_range (*this, start, end);
+ }
+
+ bool shrink (unsigned count)
+ {
+ return thiz->shrink (*this, count);
+ }
+ };
+
+ size_t get_class1_record_size () const
+ {
+ const size_t class2_count = class2Count;
+ return
+ class2_count * (valueFormat1.get_size () + valueFormat2.get_size ());
+ }
+
+ unsigned clone_range (split_context_t& split_context,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end);
+
+ graph_t& graph = split_context.c.graph;
+
+ unsigned num_records = end - start;
+ unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size
+ + num_records * split_context.class1_record_size;
+
+ unsigned pair_pos_prime_id = split_context.c.create_node (prime_size);
+ if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) graph.object (pair_pos_prime_id).head;
+ pair_pos_prime->format = this->format;
+ pair_pos_prime->valueFormat1 = this->valueFormat1;
+ pair_pos_prime->valueFormat2 = this->valueFormat2;
+ pair_pos_prime->class1Count = num_records;
+ pair_pos_prime->class2Count = this->class2Count;
+ clone_class1_records (split_context,
+ pair_pos_prime_id,
+ start,
+ end);
+
+ unsigned coverage_id =
+ graph.index_for_offset (split_context.this_index, &coverage);
+ unsigned class_def_1_id =
+ graph.index_for_offset (split_context.this_index, &classDef1);
+ auto& coverage_v = graph.vertices_[coverage_id];
+ auto& class_def_1_v = graph.vertices_[class_def_1_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+ if (!coverage_table
+ || !coverage_table->sanitize (coverage_v)
+ || !class_def_1_table
+ || !class_def_1_table->sanitize (class_def_1_v))
+ return -1;
+
+ auto klass_map =
+ + coverage_table->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+ })
+ | hb_filter ([&] (hb_codepoint_t klass) {
+ return klass >= start && klass < end;
+ }, hb_second)
+ | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) {
+ // Classes must be from 0...N so subtract start
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start);
+ })
+ ;
+
+ if (!Coverage::add_coverage (split_context.c,
+ pair_pos_prime_id,
+ 2,
+ + klass_map | hb_map_retains_sorting (hb_first),
+ split_context.max_coverage_size))
+ return -1;
+
+ // classDef1
+ if (!ClassDef::add_class_def (split_context.c,
+ pair_pos_prime_id,
+ 8,
+ + klass_map,
+ split_context.max_class_def_size))
+ return -1;
+
+ // classDef2
+ unsigned class_def_2_id =
+ graph.index_for_offset (split_context.this_index, &classDef2);
+ auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
+ class_def_link->width = SmallTypes::size;
+ class_def_link->objidx = class_def_2_id;
+ class_def_link->position = 10;
+ graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id);
+ graph.duplicate (pair_pos_prime_id, class_def_2_id);
+
+ return pair_pos_prime_id;
+ }
+
+ void clone_class1_records (split_context_t& split_context,
+ unsigned pair_pos_prime_id,
+ unsigned start, unsigned end) const
+ {
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
+
+ char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
+ unsigned num_records = end - start;
+ hb_memcpy (&pair_pos_prime->values[0],
+ start_addr,
+ num_records * split_context.class1_record_size);
+
+ if (!split_context.format1_device_table_indices
+ && !split_context.format2_device_table_indices)
+ // No device tables to move over.
+ return;
+
+ unsigned class2_count = class2Count;
+ for (unsigned i = start; i < end; i++)
+ {
+ for (unsigned j = 0; j < class2_count; j++)
+ {
+ unsigned value1_index = split_context.value_record_len * (class2_count * i + j);
+ unsigned value2_index = value1_index + split_context.value1_record_len;
+
+ unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j);
+ unsigned new_value2_index = new_value1_index + split_context.value1_record_len;
+
+ transfer_device_tables (split_context,
+ pair_pos_prime_id,
+ split_context.format1_device_table_indices,
+ value1_index,
+ new_value1_index);
+
+ transfer_device_tables (split_context,
+ pair_pos_prime_id,
+ split_context.format2_device_table_indices,
+ value2_index,
+ new_value2_index);
+ }
+ }
+ }
+
+ void transfer_device_tables (split_context_t& split_context,
+ unsigned pair_pos_prime_id,
+ const hb_vector_t<unsigned>& device_table_indices,
+ unsigned old_value_record_index,
+ unsigned new_value_record_index) const
+ {
+ PairPosFormat2* pair_pos_prime =
+ (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
+
+ for (unsigned i : device_table_indices)
+ {
+ OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i];
+ unsigned record_position = ((char*) record) - ((char*) this);
+ if (!split_context.device_tables.has (record_position)) continue;
+
+ split_context.c.graph.move_child (
+ split_context.this_index,
+ record,
+ pair_pos_prime_id,
+ (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]);
+ }
+ }
+
+ bool shrink (split_context_t& split_context,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking PairPosFormat2 (%u) to [0, %u).",
+ split_context.this_index,
+ count);
+ unsigned old_count = class1Count;
+ if (count >= old_count)
+ return true;
+
+ graph_t& graph = split_context.c.graph;
+ class1Count = count;
+ graph.vertices_[split_context.this_index].obj.tail -=
+ (old_count - count) * split_context.class1_record_size;
+
+ auto coverage =
+ graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
+ if (!coverage) return false;
+
+ auto class_def_1 =
+ graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
+ if (!class_def_1) return false;
+
+ auto klass_map =
+ + coverage.table->iter ()
+ | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
+ })
+ | hb_filter ([&] (hb_codepoint_t klass) {
+ return klass < count;
+ }, hb_second)
+ ;
+
+ auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
+ if (!Coverage::make_coverage (split_context.c,
+ + new_coverage,
+ coverage.index,
+ // existing ranges my not be kept, worst case size is a format 1
+ // coverage table.
+ 4 + new_coverage.len() * 2))
+ return false;
+
+ return ClassDef::make_class_def (split_context.c,
+ + klass_map,
+ class_def_1.index,
+ class_def_1.vertex->table_size ());
+ }
+
+ hb_hashmap_t<unsigned, unsigned>
+ get_all_device_tables (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
+ {
+ const auto& v = c.graph.vertices_[this_index];
+ return v.position_to_index_map ();
+ }
+
+ const Coverage* get_coverage (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
+ {
+ unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table || !coverage_table->sanitize (coverage_v))
+ return &Null(Coverage);
+ return coverage_table;
+ }
+
+ const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c,
+ unsigned this_index) const
+ {
+ unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1);
+ auto& class_def_1_v = c.graph.vertices_[class_def_1_id];
+
+ ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+ if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v))
+ return &Null(ClassDef);
+ return class_def_1_table;
+ }
+
+ unsigned size_of_value_record_children (gsubgpos_graph_context_t& c,
+ const hb_hashmap_t<unsigned, unsigned>& device_tables,
+ const hb_vector_t<unsigned> device_table_indices,
+ unsigned value_record_index,
+ hb_set_t& visited)
+ {
+ unsigned size = 0;
+ for (unsigned i : device_table_indices)
+ {
+ OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i];
+ unsigned record_position = ((char*) record) - ((char*) this);
+ unsigned* obj_idx;
+ if (!device_tables.has (record_position, &obj_idx)) continue;
+ size += c.graph.find_subgraph_size (*obj_idx, visited);
+ }
+ return size;
+ }
+
+ unsigned size_of (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ const void* offset) const
+ {
+ const unsigned id = c.graph.index_for_offset (this_index, offset);
+ return c.graph.vertices_[id].table_size ();
+ }
+};
+
+struct PairPos : public OT::Layout::GPOS_impl::PairPos
+{
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
+ {
+ switch (u.format) {
+ case 1:
+ return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+ case 2:
+ return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
+#ifndef HB_NO_BEYOND_64K
+ case 3: HB_FALLTHROUGH;
+ case 4: HB_FALLTHROUGH;
+ // Don't split 24bit PairPos's.
+#endif
+ default:
+ return hb_vector_t<unsigned> ();
+ }
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < u.format.get_size ()) return false;
+
+ switch (u.format) {
+ case 1:
+ return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
+ case 2:
+ return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+ case 3: HB_FALLTHROUGH;
+ case 4: HB_FALLTHROUGH;
+#endif
+ default:
+ // We don't handle format 3 and 4 here.
+ return false;
+ }
+ }
+};
+
+}
+
+#endif // GRAPH_PAIRPOS_GRAPH_HH
diff --git a/src/graph/serialize.hh b/src/graph/serialize.hh
new file mode 100644
index 000000000..d03a61bd1
--- /dev/null
+++ b/src/graph/serialize.hh
@@ -0,0 +1,270 @@
+/*
+ * 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;
+
+ bool operator != (const overflow_record_t o) const
+ { return !(*this == o); }
+
+ inline bool operator == (const overflow_record_t& o) const
+ {
+ return parent == o.parent &&
+ child == o.child;
+ }
+
+ inline uint32_t hash () const
+ {
+ uint32_t current = 0;
+ current = current * 31 + hb_hash (parent);
+ current = current * 31 + hb_hash (child);
+ return current;
+ }
+};
+
+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 ();
+
+ hb_hashmap_t<overflow_record_t*, bool> record_set;
+ 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;
+ if (record_set.has(&r)) continue; // don't keep duplicate overflows.
+
+ overflows->push (r);
+ record_set.set(&r, true);
+ }
+ }
+
+ 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;
+ }
+
+ hb_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/src/graph/split-helpers.hh b/src/graph/split-helpers.hh
new file mode 100644
index 000000000..61fd7c2d2
--- /dev/null
+++ b/src/graph/split-helpers.hh
@@ -0,0 +1,69 @@
+/*
+ * 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_SPLIT_HELPERS_HH
+#define GRAPH_SPLIT_HELPERS_HH
+
+namespace graph {
+
+template<typename Context>
+HB_INTERNAL
+hb_vector_t<unsigned> actuate_subtable_split (Context& split_context,
+ const hb_vector_t<unsigned>& split_points)
+{
+ hb_vector_t<unsigned> new_objects;
+ if (!split_points)
+ return new_objects;
+
+ for (unsigned i = 0; i < split_points.length; i++)
+ {
+ unsigned start = split_points[i];
+ unsigned end = (i < split_points.length - 1)
+ ? split_points[i + 1]
+ : split_context.original_count ();
+ unsigned id = split_context.clone_range (start, end);
+
+ if (id == (unsigned) -1)
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ return new_objects;
+ }
+ new_objects.push (id);
+ }
+
+ if (!split_context.shrink (split_points[0]))
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ }
+
+ return new_objects;
+}
+
+}
+
+#endif // GRAPH_SPLIT_HELPERS_HH
diff --git a/src/graph/test-classdef-graph.cc b/src/graph/test-classdef-graph.cc
new file mode 100644
index 000000000..55854ff5c
--- /dev/null
+++ b/src/graph/test-classdef-graph.cc
@@ -0,0 +1,119 @@
+/*
+ * 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
+ */
+
+#include "gsubgpos-context.hh"
+#include "classdef-graph.hh"
+
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t;
+typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+
+
+static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
+ unsigned cov_expected, unsigned class_def_expected)
+{
+ graph::class_def_size_estimator_t estimator (list.iter ());
+
+ unsigned result = estimator.incremental_coverage_size (klass);
+ if (result != cov_expected)
+ {
+ printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+ return false;
+ }
+
+ result = estimator.incremental_class_def_size (klass);
+ if (result != class_def_expected)
+ {
+ printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+ return false;
+ }
+
+ return true;
+}
+
+static void test_class_and_coverage_size_estimates ()
+{
+ gid_and_class_list_t empty = {
+ };
+ assert (incremental_size_is (empty, 0, 0, 0));
+ assert (incremental_size_is (empty, 1, 0, 0));
+
+ gid_and_class_list_t class_zero = {
+ {5, 0},
+ };
+ assert (incremental_size_is (class_zero, 0, 2, 0));
+
+ gid_and_class_list_t consecutive = {
+ {4, 0},
+ {5, 0},
+ {6, 1},
+ {7, 1},
+ {8, 2},
+ {9, 2},
+ {10, 2},
+ {11, 2},
+ };
+ assert (incremental_size_is (consecutive, 0, 4, 0));
+ assert (incremental_size_is (consecutive, 1, 4, 4));
+ assert (incremental_size_is (consecutive, 2, 8, 6));
+
+ gid_and_class_list_t non_consecutive = {
+ {4, 0},
+ {5, 0},
+
+ {6, 1},
+ {7, 1},
+
+ {9, 2},
+ {10, 2},
+ {11, 2},
+ {12, 2},
+ };
+ assert (incremental_size_is (non_consecutive, 0, 4, 0));
+ assert (incremental_size_is (non_consecutive, 1, 4, 6));
+ assert (incremental_size_is (non_consecutive, 2, 8, 6));
+
+ gid_and_class_list_t multiple_ranges = {
+ {4, 0},
+ {5, 0},
+
+ {6, 1},
+ {7, 1},
+
+ {9, 1},
+
+ {11, 1},
+ {12, 1},
+ {13, 1},
+ };
+ assert (incremental_size_is (multiple_ranges, 0, 4, 0));
+ assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+}
+
+int
+main (int argc, char **argv)
+{
+ test_class_and_coverage_size_estimates ();
+}
diff --git a/src/harfbuzz-config.cmake.in b/src/harfbuzz-config.cmake.in
index 304410d9b..0de082c2a 100644
--- a/src/harfbuzz-config.cmake.in
+++ b/src/harfbuzz-config.cmake.in
@@ -1,29 +1,5 @@
-# Set these variables so that the `${prefix}/lib` expands to something we can
-# remove.
-set(_harfbuzz_remove_string "REMOVE_ME")
-set(exec_prefix "${_harfbuzz_remove_string}")
-set(prefix "${_harfbuzz_remove_string}")
-
-# Compute the installation prefix by stripping components from our current
-# location.
-get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
-get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
set(_harfbuzz_libdir "@libdir@")
-string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}")
-set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}")
-while (_harfbuzz_libdir_iter)
- set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}")
- get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY)
- if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter)
- break()
- endif ()
- get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
-endwhile ()
-unset(_harfbuzz_libdir_iter)
-
-# Get the include subdir.
set(_harfbuzz_includedir "@includedir@")
-string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}")
# Extract version information from libtool.
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
@@ -48,29 +24,29 @@ endif ()
# Add the libraries.
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
set_target_properties(harfbuzz::harfbuzz PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
- IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
+ INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
+ IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
add_library(harfbuzz::icu SHARED IMPORTED)
set_target_properties(harfbuzz::icu PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+ INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
- IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
+ IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
add_library(harfbuzz::subset SHARED IMPORTED)
set_target_properties(harfbuzz::subset PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+ INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
- IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
+ IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
# Only add the gobject library if it was built.
set(_harfbuzz_have_gobject "@have_gobject@")
if (_harfbuzz_have_gobject)
add_library(harfbuzz::gobject SHARED IMPORTED)
set_target_properties(harfbuzz::gobject PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+ INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
- IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
+ IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
endif ()
# Clean out variables we used in our scope.
@@ -80,7 +56,3 @@ unset(_harfbuzz_revision)
unset(_harfbuzz_age)
unset(_harfbuzz_includedir)
unset(_harfbuzz_libdir)
-unset(_harfbuzz_prefix)
-unset(exec_prefix)
-unset(prefix)
-unset(_harfbuzz_remove_string)
diff --git a/src/harfbuzz-subset.cc b/src/harfbuzz-subset.cc
new file mode 100644
index 000000000..a43485e6f
--- /dev/null
+++ b/src/harfbuzz-subset.cc
@@ -0,0 +1,57 @@
+#include "graph/gsubgpos-context.cc"
+#include "hb-aat-layout.cc"
+#include "hb-aat-map.cc"
+#include "hb-blob.cc"
+#include "hb-buffer-serialize.cc"
+#include "hb-buffer-verify.cc"
+#include "hb-buffer.cc"
+#include "hb-common.cc"
+#include "hb-draw.cc"
+#include "hb-face.cc"
+#include "hb-fallback-shape.cc"
+#include "hb-font.cc"
+#include "hb-map.cc"
+#include "hb-number.cc"
+#include "hb-ot-cff1-table.cc"
+#include "hb-ot-cff2-table.cc"
+#include "hb-ot-color.cc"
+#include "hb-ot-face.cc"
+#include "hb-ot-font.cc"
+#include "hb-ot-layout.cc"
+#include "hb-ot-map.cc"
+#include "hb-ot-math.cc"
+#include "hb-ot-meta.cc"
+#include "hb-ot-metrics.cc"
+#include "hb-ot-name.cc"
+#include "hb-ot-shape-fallback.cc"
+#include "hb-ot-shape-normalize.cc"
+#include "hb-ot-shape.cc"
+#include "hb-ot-shaper-arabic.cc"
+#include "hb-ot-shaper-default.cc"
+#include "hb-ot-shaper-hangul.cc"
+#include "hb-ot-shaper-hebrew.cc"
+#include "hb-ot-shaper-indic-table.cc"
+#include "hb-ot-shaper-indic.cc"
+#include "hb-ot-shaper-khmer.cc"
+#include "hb-ot-shaper-myanmar.cc"
+#include "hb-ot-shaper-syllabic.cc"
+#include "hb-ot-shaper-thai.cc"
+#include "hb-ot-shaper-use.cc"
+#include "hb-ot-shaper-vowel-constraints.cc"
+#include "hb-ot-tag.cc"
+#include "hb-ot-var.cc"
+#include "hb-set.cc"
+#include "hb-shape-plan.cc"
+#include "hb-shape.cc"
+#include "hb-shaper.cc"
+#include "hb-static.cc"
+#include "hb-style.cc"
+#include "hb-subset-cff-common.cc"
+#include "hb-subset-cff1.cc"
+#include "hb-subset-cff2.cc"
+#include "hb-subset-input.cc"
+#include "hb-subset-plan.cc"
+#include "hb-subset-repacker.cc"
+#include "hb-subset.cc"
+#include "hb-ucd.cc"
+#include "hb-unicode.cc"
diff --git a/src/harfbuzz-subset.pc.in b/src/harfbuzz-subset.pc.in
index 5da64b3f1..ca13c70ef 100644
--- a/src/harfbuzz-subset.pc.in
+++ b/src/harfbuzz-subset.pc.in
@@ -3,10 +3,10 @@ exec_prefix=%exec_prefix%
libdir=%libdir%
includedir=%includedir%
-Name: harfbuzz
+Name: harfbuzz subsetter
Description: HarfBuzz font subsetter
Version: %VERSION%
-Requires: harfbuzz
+Requires: harfbuzz = %VERSION%
Libs: -L${libdir} -lharfbuzz-subset
Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc
index 14ee6f5e8..fe4e21db0 100644
--- a/src/harfbuzz.cc
+++ b/src/harfbuzz.cc
@@ -2,14 +2,20 @@
#include "hb-aat-map.cc"
#include "hb-blob.cc"
#include "hb-buffer-serialize.cc"
+#include "hb-buffer-verify.cc"
#include "hb-buffer.cc"
#include "hb-common.cc"
+#include "hb-coretext.cc"
+#include "hb-directwrite.cc"
#include "hb-draw.cc"
#include "hb-face.cc"
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
+#include "hb-ft.cc"
+#include "hb-gdi.cc"
+#include "hb-glib.cc"
+#include "hb-graphite2.cc"
#include "hb-map.cc"
-#include "hb-ms-feature-ranges.cc"
#include "hb-number.cc"
#include "hb-ot-cff1-table.cc"
#include "hb-ot-cff2-table.cc"
@@ -22,21 +28,21 @@
#include "hb-ot-meta.cc"
#include "hb-ot-metrics.cc"
#include "hb-ot-name.cc"
-#include "hb-ot-shape-complex-arabic.cc"
-#include "hb-ot-shape-complex-default.cc"
-#include "hb-ot-shape-complex-hangul.cc"
-#include "hb-ot-shape-complex-hebrew.cc"
-#include "hb-ot-shape-complex-indic-table.cc"
-#include "hb-ot-shape-complex-indic.cc"
-#include "hb-ot-shape-complex-khmer.cc"
-#include "hb-ot-shape-complex-myanmar.cc"
-#include "hb-ot-shape-complex-syllabic.cc"
-#include "hb-ot-shape-complex-thai.cc"
-#include "hb-ot-shape-complex-use.cc"
-#include "hb-ot-shape-complex-vowel-constraints.cc"
#include "hb-ot-shape-fallback.cc"
#include "hb-ot-shape-normalize.cc"
#include "hb-ot-shape.cc"
+#include "hb-ot-shaper-arabic.cc"
+#include "hb-ot-shaper-default.cc"
+#include "hb-ot-shaper-hangul.cc"
+#include "hb-ot-shaper-hebrew.cc"
+#include "hb-ot-shaper-indic-table.cc"
+#include "hb-ot-shaper-indic.cc"
+#include "hb-ot-shaper-khmer.cc"
+#include "hb-ot-shaper-myanmar.cc"
+#include "hb-ot-shaper-syllabic.cc"
+#include "hb-ot-shaper-thai.cc"
+#include "hb-ot-shaper-use.cc"
+#include "hb-ot-shaper-vowel-constraints.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-set.cc"
@@ -47,10 +53,4 @@
#include "hb-style.cc"
#include "hb-ucd.cc"
#include "hb-unicode.cc"
-#include "hb-glib.cc"
-#include "hb-ft.cc"
-#include "hb-graphite2.cc"
#include "hb-uniscribe.cc"
-#include "hb-gdi.cc"
-#include "hb-directwrite.cc"
-#include "hb-coretext.cc"
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index b52844e75..bf12d2e69 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -42,7 +42,7 @@ struct BaselineTableFormat0Part
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -78,7 +78,7 @@ struct BaselineTableFormat2Part
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 1dcbe9290..6cbed8269 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -415,18 +415,7 @@ struct Lookup
public:
DEFINE_SIZE_UNION (2, format);
};
-/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
- * special NULL objects for Lookup<> objects, but since it's template our macros
- * don't work. So we have to hand-code them here. UGLY. */
-} /* Close namespace. */
-/* Ugly hand-coded null objects for template Lookup<> :(. */
-extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
-template <typename T>
-struct Null<AAT::Lookup<T>> {
- static AAT::Lookup<T> const & get_null ()
- { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
-};
-namespace AAT {
+DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
enum { DELETED_GLYPH = 0xFFFF };
@@ -681,6 +670,13 @@ struct ObsoleteTypes
const void *base,
const T *array)
{
+ /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
+ /* If offset is less than base, return an offset that would
+ * result in an address half a 32bit address-space away,
+ * to make sure sanitize fails even on 32bit builds. */
+ if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
+ return INT_MAX / T::static_size;
+
/* https://github.com/harfbuzz/harfbuzz/issues/2816 */
return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
}
@@ -839,7 +835,7 @@ struct StateTableDriver
}
if (!c->in_place)
- buffer->swap_buffers ();
+ buffer->sync ();
}
public:
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index 573f0cf9f..815a1fd2a 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -62,7 +62,7 @@ struct SettingName
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index d745c1143..8fd3990f8 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -48,7 +48,7 @@ struct ActionSubrecordHeader
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
HBUINT16 actionClass; /* The JustClass value associated with this
@@ -65,14 +65,14 @@ struct DecompositionAction
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
ActionSubrecordHeader
header;
- HBFixed lowerLimit; /* If the distance factor is less than this value,
+ F16DOT16 lowerLimit; /* If the distance factor is less than this value,
* then the ligature is decomposed. */
- HBFixed upperLimit; /* If the distance factor is greater than this value,
+ F16DOT16 upperLimit; /* If the distance factor is greater than this value,
* then the ligature is decomposed. */
HBUINT16 order; /* Numerical order in which this ligature will
* be decomposed; you may want infrequent ligatures
@@ -112,13 +112,13 @@ struct ConditionalAddGlyphAction
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
ActionSubrecordHeader
header;
- HBFixed substThreshold; /* Distance growth factor (in ems) at which
+ F16DOT16 substThreshold; /* Distance growth factor (in ems) at which
* this glyph is replaced and the growth factor
* recalculated. */
HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is
@@ -137,7 +137,7 @@ struct DuctileGlyphAction
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -146,13 +146,13 @@ struct DuctileGlyphAction
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
* This would normally be 0x64756374 ('duct'),
* but you may use any axis the font contains. */
- HBFixed minimumLimit; /* The lowest value for the ductility axis tha
+ F16DOT16 minimumLimit; /* The lowest value for the ductility axis that
* still yields an acceptable appearance. Normally
* this will be 1.0. */
- HBFixed noStretchValue; /* This is the default value that corresponds to
+ F16DOT16 noStretchValue; /* This is the default value that corresponds to
* no change in appearance. Normally, this will
* be 1.0. */
- HBFixed maximumLimit; /* The highest value for the ductility axis that
+ F16DOT16 maximumLimit; /* The highest value for the ductility axis that
* still yields an acceptable appearance. */
public:
DEFINE_SIZE_STATIC (22);
@@ -163,7 +163,7 @@ struct RepeatedAddGlyphAction
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
};
protected:
- HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
+ F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the
* glyph is permitted to grow on the left or top side. */
- HBFixed beforeShrinkLimit;
+ F16DOT16 beforeShrinkLimit;
/* The ratio by which the advance width of the
* glyph is permitted to shrink on the left or top side. */
- HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
+ F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph
* is permitted to shrink on the left or top side. */
- HBFixed afterShrinkLimit;
+ F16DOT16 afterShrinkLimit;
/* The ratio by which the advance width of the glyph
* is at most permitted to shrink on the right or
* bottom side. */
@@ -294,7 +294,7 @@ struct WidthDeltaPair
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index 0354b47d5..995492cd5 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/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;
}
@@ -751,7 +751,7 @@ struct KerxSubTableHeader
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
public:
@@ -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/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index b77c1f4d4..8b9190d0b 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/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);
@@ -131,14 +131,14 @@ struct RearrangementSubtable
hb_glyph_info_t *info = buffer->info;
hb_glyph_info_t buf[4];
- memcpy (buf, info + start, l * sizeof (buf[0]));
- memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
+ hb_memcpy (buf, info + start, l * sizeof (buf[0]));
+ hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
if (l != r)
memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
- memcpy (info + start, buf + 2, r * sizeof (buf[0]));
- memcpy (info + end - l, buf, l * sizeof (buf[0]));
+ hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
+ hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
if (reverse_l)
{
buf[0] = info[end - 1];
@@ -980,6 +980,15 @@ struct Chain
setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
goto retry;
}
+#ifndef HB_NO_AAT
+ else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
+ /* TODO: Rudimentary language matching. */
+ hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
+ {
+ flags &= feature.disableFlags;
+ flags |= feature.enableFlags;
+ }
+#endif
}
}
return flags;
diff --git a/src/hb-aat-layout-opbd-table.hh b/src/hb-aat-layout-opbd-table.hh
index b1a151282..51b650fc3 100644
--- a/src/hb-aat-layout-opbd-table.hh
+++ b/src/hb-aat-layout-opbd-table.hh
@@ -42,7 +42,7 @@ struct OpticalBounds
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
FWORD leftSide;
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index 68bcb2396..2ba9355b0 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -62,7 +62,7 @@ struct TrackTableEntry
}
protected:
- HBFixed track; /* Track value for this record. */
+ F16DOT16 track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
@@ -82,7 +82,7 @@ struct TrackData
const void *base) const
{
unsigned int sizes = nSizes;
- hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+ hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
@@ -120,7 +120,7 @@ struct TrackData
if (!sizes) return 0.;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
- hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+ hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem)
@@ -141,7 +141,7 @@ struct TrackData
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
- NNOffset32To<UnsizedArrayOf<HBFixed>>
+ NNOffset32To<UnsizedArrayOf<F16DOT16>>
sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index e2d4de2cc..78427b0d5 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -108,7 +108,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
- {HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
+ {HB_TAG ('h','i','s','t'), (hb_aat_layout_feature_type_t) 40, (hb_aat_layout_feature_selector_t) 0, (hb_aat_layout_feature_selector_t) 1},
{HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF},
{HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION},
@@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
+ {HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
@@ -170,6 +171,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF},
{HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
+ {HB_TAG ('v','r','t','r'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, (hb_aat_layout_feature_selector_t) 2, (hb_aat_layout_feature_selector_t) 3},
{HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
};
@@ -228,7 +230,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
*
* <note>Note: does not examine the `GSUB` table.</note>
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.3.0
*/
@@ -287,7 +289,7 @@ is_deleted_glyph (const hb_glyph_info_t *info)
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
- hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
+ buffer->delete_glyphs_inplace (is_deleted_glyph);
}
/**
@@ -299,7 +301,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
*
* <note>Note: does not examine the `GPOS` table.</note>
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.3.0
*/
@@ -332,7 +334,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
* Tests whether the specified face includes any tracking information
* in the `trak` table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.3.0
*/
diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh
index 5a0fa7054..d0ee7d672 100644
--- a/src/hb-aat-map.hh
+++ b/src/hb-aat-map.hh
@@ -38,7 +38,7 @@ struct hb_aat_map_t
void init ()
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
chain_flags.init ();
}
void fini () { chain_flags.fini (); }
@@ -52,8 +52,9 @@ struct hb_aat_map_builder_t
public:
HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
- const hb_segment_properties_t *props_ HB_UNUSED) :
- face (face_) {}
+ const hb_segment_properties_t props_) :
+ face (face_),
+ props (props_) {}
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
@@ -87,6 +88,7 @@ struct hb_aat_map_builder_t
public:
hb_face_t *face;
+ hb_segment_properties_t props;
public:
hb_sorted_vector_t<feature_info_t> features;
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 446d87e28..d85a4afe1 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -36,6 +36,7 @@
#include <algorithm>
#include <initializer_list>
+#include <functional>
#include <new>
/*
@@ -58,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; } \
@@ -108,15 +109,16 @@ struct BEInt<Type, 2>
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
constexpr operator Type () const
{
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((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_bswap16 (((packed_uint16_t *) this)->v);
+ return __builtin_bswap16 (((packed_uint16_t *) v)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
- return ((packed_uint16_t *) this)->v;
+ return ((packed_uint16_t *) v)->v;
#endif
#else
return (v[0] << 8)
@@ -149,10 +151,27 @@ 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(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((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 *) v)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ return ((packed_uint32_t *) v)->v;
+#endif
+#else
+ return (v[0] << 24)
+ + (v[1] << 16)
+ + (v[2] << 8)
+ + (v[3] );
+#endif
+ }
private: uint8_t v[4];
};
@@ -217,13 +236,8 @@ struct
template <typename T> constexpr auto
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
- 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:
@@ -435,23 +449,29 @@ struct
private:
template <typename T1, typename T2> auto
- impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
+ impl (T1&& v1, T2 &&v2, hb_priority<3>) const HB_AUTO_RETURN
(
std::forward<T2> (v2).cmp (std::forward<T1> (v1)) == 0
)
template <typename T1, typename T2> auto
- impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
+ impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
(
std::forward<T1> (v1).cmp (std::forward<T2> (v2)) == 0
)
template <typename T1, typename T2> auto
- impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
+ impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
(
std::forward<T1> (v1) == std::forward<T2> (v2)
)
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
+ (
+ std::forward<T2> (v2) == std::forward<T1> (v1)
+ )
+
public:
template <typename T1, typename T2> auto
@@ -464,6 +484,17 @@ struct
}
HB_FUNCOBJ (hb_equal);
+struct
+{
+ template <typename T> void
+ operator () (T& a, T& b) const
+ {
+ using std::swap; // allow ADL
+ swap (a, b);
+ }
+}
+HB_FUNCOBJ (hb_swap);
+
template <typename T1, typename T2>
struct hb_pair_t
@@ -472,11 +503,15 @@ struct hb_pair_t
typedef T2 second_t;
typedef hb_pair_t<T1, T2> pair_t;
- hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
+ template <typename U1 = T1, typename U2 = T2,
+ hb_enable_if (std::is_default_constructible<U1>::value &&
+ std::is_default_constructible<U2>::value)>
+ hb_pair_t () : first (), second () {}
+ hb_pair_t (T1 a, T2 b) : first (std::forward<T1> (a)), second (std::forward<T2> (b)) {}
template <typename Q1, typename Q2,
hb_enable_if (hb_is_convertible (T1, Q1) &&
- hb_is_convertible (T2, T2))>
+ hb_is_convertible (T2, Q2))>
operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
hb_pair_t<T1, T2> reverse () const
@@ -489,10 +524,28 @@ struct hb_pair_t
bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
bool operator <= (const pair_t& o) const { return !(*this > o); }
+ static int cmp (const void *pa, const void *pb)
+ {
+ pair_t *a = (pair_t *) pa;
+ pair_t *b = (pair_t *) pb;
+
+ if (a->first < b->first) return -1;
+ if (a->first > b->first) return +1;
+ if (a->second < b->second) return -1;
+ if (a->second > b->second) return +1;
+ return 0;
+ }
+
+ friend void swap (hb_pair_t& a, hb_pair_t& b)
+ {
+ hb_swap (a.first, b.first);
+ hb_swap (a.second, b.second);
+ }
+
+
T1 first;
T2 second;
};
-#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
@@ -518,14 +571,14 @@ struct
{
template <typename T, typename T2> constexpr auto
operator () (T&& a, T2&& b) const HB_AUTO_RETURN
- (a <= b ? std::forward<T> (a) : std::forward<T2> (b))
+ (a <= b ? a : b)
}
HB_FUNCOBJ (hb_min);
struct
{
template <typename T, typename T2> constexpr auto
operator () (T&& a, T2&& b) const HB_AUTO_RETURN
- (a >= b ? std::forward<T> (a) : std::forward<T2> (b))
+ (a >= b ? a : b)
}
HB_FUNCOBJ (hb_max);
struct
@@ -536,17 +589,6 @@ struct
}
HB_FUNCOBJ (hb_clamp);
-struct
-{
- template <typename T> void
- operator () (T& a, T& b) const
- {
- using std::swap; // allow ADL
- swap (a, b);
- }
-}
-HB_FUNCOBJ (hb_swap);
-
/*
* Bithacks.
*/
@@ -815,14 +857,14 @@ hb_in_range (T u, T lo, T hi)
return (T)(u - lo) <= (T)(hi - lo);
}
template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+hb_in_ranges (T u, T lo1, T hi1)
{
- return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+ return hb_in_range (u, lo1, hi1);
}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+template <typename T, typename ...Ts> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
{
- return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
+ return hb_in_range<T> (u, lo1, hi1) || hb_in_ranges<T> (u, ds...);
}
@@ -830,10 +872,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
* Overflow checking.
*/
-/* Consider __builtin_mul_overflow use here also */
static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
{
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+ unsigned stack_result;
+ if (!result)
+ result = &stack_result;
+ return __builtin_mul_overflow (count, size, result);
+#endif
+
+ if (result)
+ *result = count * size;
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
@@ -870,7 +920,7 @@ hb_bsearch_impl (unsigned *pos, /* Out */
#pragma GCC diagnostic ignored "-Wcast-align"
V* p = (V*) (((const char *) base) + (mid * stride));
#pragma GCC diagnostic pop
- int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...);
+ int c = compar ((const void *) std::addressof (key), (const void *) p, ds...);
if (c < 0)
max = mid - 1;
else if (c > 0)
@@ -934,7 +984,7 @@ void hb_qsort(void *base, size_t nel, size_t width,
[void *arg]);
*/
-#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp))
/* swap a and b */
/* a and b must not be equal! */
@@ -1125,9 +1175,12 @@ hb_qsort (void *base, size_t nel, size_t width,
}
-template <typename T, typename T2, typename T3> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
+template <typename T, typename T2, typename T3 = int> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr)
{
+ static_assert (hb_is_trivially_copy_assignable (T), "");
+ static_assert (hb_is_trivially_copy_assignable (T3), "");
+
for (unsigned int i = 1; i < len; i++)
{
unsigned int j = i;
@@ -1150,12 +1203,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *)
}
}
-template <typename T> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
-{
- hb_stable_sort (array, len, compar, (int *) nullptr);
-}
-
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
@@ -1283,47 +1330,4 @@ struct
HB_FUNCOBJ (hb_dec);
-/* Compiler-assisted vectorization. */
-
-/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * basically a fixed-size bitset. */
-template <typename elt_t, unsigned int byte_size>
-struct hb_vector_size_t
-{
- elt_t& operator [] (unsigned int i) { return v[i]; }
- const elt_t& operator [] (unsigned int i) const { return v[i]; }
-
- void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
-
- template <typename Op>
- hb_vector_size_t process (const Op& op) const
- {
- hb_vector_size_t r;
- for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
- r.v[i] = op (v[i]);
- return r;
- }
- template <typename Op>
- hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
- {
- hb_vector_size_t r;
- for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
- r.v[i] = op (v[i], o.v[i]);
- return r;
- }
- hb_vector_size_t operator | (const hb_vector_size_t &o) const
- { return process (hb_bitwise_or, o); }
- hb_vector_size_t operator & (const hb_vector_size_t &o) const
- { return process (hb_bitwise_and, o); }
- hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
- { return process (hb_bitwise_xor, o); }
- hb_vector_size_t operator ~ () const
- { return process (hb_bitwise_neg); }
-
- private:
- static_assert (0 == byte_size % sizeof (elt_t), "");
- elt_t v[byte_size / sizeof (elt_t)];
-};
-
-
#endif /* HB_ALGS_HH */
diff --git a/src/hb-array.hh b/src/hb-array.hh
index dd61509b2..17562bc33 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -51,13 +51,18 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
* Constructors.
*/
hb_array_t () = default;
- hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
+ hb_array_t (const hb_array_t&) = default;
+ ~hb_array_t () = default;
+ hb_array_t& operator= (const hb_array_t&) = default;
+ hb_array_t& operator= (hb_array_t&&) = default;
+
+ constexpr hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
template <unsigned int length_>
- hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {}
+ constexpr hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {}
template <typename U,
hb_enable_if (hb_is_cr_convertible(U, Type))>
- hb_array_t (const hb_array_t<U> &o) :
+ constexpr hb_array_t (const hb_array_t<U> &o) :
hb_iter_with_fallback_t<hb_array_t, Type&> (),
arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
template <typename U,
@@ -95,10 +100,17 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
* it's best if we can just compare arrayZ, though comparing contents is still fast,
* but also would require that Type has operator==. As such, we optimize this operator
- * for range-based for loop and just compare arrayZ. No need to compare length, as we
- * assume we're only compared to .end(). */
+ * for range-based for loop and just compare arrayZ and length.
+ *
+ * The above comment is outdated now because we implemented separate begin/end to
+ * objects that were using hb_array_t for range-based loop before. */
bool operator != (const hb_array_t& o) const
- { return arrayZ != o.arrayZ; }
+ { return this->arrayZ != o.arrayZ || this->length != o.length; }
+
+ /* Faster range-based for loop without bounds-check. */
+ Type *begin () const { return arrayZ; }
+ Type *end () const { return arrayZ + length; }
+
/* Extra operators.
*/
@@ -108,11 +120,11 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
HB_INTERNAL bool operator == (const hb_array_t &o) const;
- uint32_t hash () const {
+ uint32_t hash () const
+ {
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++) {
- current = current * 31 + hb_hash (this->arrayZ[i]);
- }
+ for (auto &v : *this)
+ current = current * 31 + hb_hash (v);
return current;
}
@@ -180,23 +192,18 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
{
+ //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
if (likely (length))
hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
return hb_sorted_array_t<Type> (*this);
}
hb_sorted_array_t<Type> qsort ()
{
+ //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
if (likely (length))
hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
return hb_sorted_array_t<Type> (*this);
}
- void qsort (unsigned int start, unsigned int end)
- {
- end = hb_min (end, length);
- assert (start <= end);
- if (likely (start < end))
- hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
- }
/*
* Other methods.
@@ -215,11 +222,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
if (end < start + 2)
return;
- for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
- Type temp = arrayZ[rhs];
- arrayZ[rhs] = arrayZ[lhs];
- arrayZ[lhs] = temp;
- }
+ for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
+ hb_swap (arrayZ[rhs], arrayZ[lhs]);
}
hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
@@ -261,17 +265,31 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
void fini ()
{ hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
- template <typename hb_serialize_context_t>
+ template <typename hb_serialize_context_t,
+ typename U = Type,
+ hb_enable_if (!(sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>)))>
hb_array_t copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto* out = c->start_embed (arrayZ);
- if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
+ if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
for (unsigned i = 0; i < length; i++)
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
return_trace (hb_array_t (out, length));
}
+ template <typename hb_serialize_context_t,
+ typename U = Type,
+ hb_enable_if (sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>))>
+ hb_array_t copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ auto* out = c->start_embed (arrayZ);
+ if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
+ hb_memcpy (out, arrayZ, get_size ());
+ return_trace (hb_array_t (out, length));
+ }
+
template <typename hb_sanitize_context_t>
bool sanitize (hb_sanitize_context_t *c) const
{ return c->check_array (arrayZ, length); }
@@ -294,8 +312,8 @@ hb_array (T (&array_)[length_])
template <typename Type>
struct hb_sorted_array_t :
- hb_iter_t<hb_sorted_array_t<Type>, Type&>,
- hb_array_t<Type>
+ hb_array_t<Type>,
+ hb_iter_t<hb_sorted_array_t<Type>, Type&>
{
typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
HB_ITER_USING (iter_base_t);
@@ -303,24 +321,36 @@ struct hb_sorted_array_t :
static constexpr bool is_sorted_iterator = true;
hb_sorted_array_t () = default;
- hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
+ hb_sorted_array_t (const hb_sorted_array_t&) = default;
+ ~hb_sorted_array_t () = default;
+ 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 (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
template <unsigned int length_>
- hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
+ constexpr hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
template <typename U,
hb_enable_if (hb_is_cr_convertible(U, Type))>
- hb_sorted_array_t (const hb_array_t<U> &o) :
- hb_iter_t<hb_sorted_array_t, Type&> (),
- hb_array_t<Type> (o) {}
+ constexpr hb_sorted_array_t (const hb_array_t<U> &o) :
+ hb_array_t<Type> (o),
+ hb_iter_t<hb_sorted_array_t, Type&> () {}
template <typename U,
hb_enable_if (hb_is_cr_convertible(U, Type))>
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
{ hb_array_t<Type> (*this) = o; return *this; }
/* Iterator implementation. */
+
+ /* See comment in hb_array_of::operator != */
bool operator != (const hb_sorted_array_t& o) const
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
+ /* Faster range-based for loop without bounds-check. */
+ Type *begin () const { return this->arrayZ; }
+ Type *end () const { return this->arrayZ + this->length; }
+
+
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
{ return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
@@ -372,15 +402,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...>,
+ std::forward<Ts> (ds)...);
}
};
template <typename T> inline hb_sorted_array_t<T>
@@ -391,7 +422,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++) {
@@ -399,22 +430,55 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
}
return true;
}
+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);
+}
+
-/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
+/* Specialize hash() for byte arrays. */
template <>
-inline uint32_t hb_array_t<const char>::hash () const {
+inline uint32_t hb_array_t<const char>::hash () const
+{
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++)
- current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+ unsigned i = 0;
+
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ for (; i + 4 <= this->length; i += 4)
+ current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
+#endif
+
+ for (; i < this->length; i++)
+ current = current * 31 + hb_hash (this->arrayZ[i]);
return current;
}
template <>
-inline uint32_t hb_array_t<const unsigned char>::hash () const {
+inline uint32_t hb_array_t<const unsigned char>::hash () const
+{
uint32_t current = 0;
- for (unsigned int i = 0; i < this->length; i++)
- current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+ unsigned i = 0;
+
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ for (; i + 4 <= this->length; i += 4)
+ current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
+#endif
+
+ for (; i < this->length; i++)
+ current = current * 31 + hb_hash (this->arrayZ[i]);
return current;
}
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index e640d1b58..14c6fb326 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -111,6 +111,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#endif
+#ifndef _hb_compiler_memory_r_barrier
+/* This we always use std::atomic for; and should never be disabled...
+ * except that MSVC gives me an internal compiler error on it. */
+#if !defined(_MSC_VER)
+#include <atomic>
+#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
+#else
+#define _hb_compiler_memory_r_barrier() do {} while (0)
+#endif
+#endif
+
+
+
#ifndef _hb_memory_r_barrier
#define _hb_memory_r_barrier() _hb_memory_barrier ()
#endif
@@ -146,10 +159,13 @@ struct hb_atomic_int_t
hb_atomic_int_t () = default;
constexpr hb_atomic_int_t (int v) : v (v) {}
+ hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
+ operator int () const { return get_relaxed (); }
+
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
- void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
+ void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
- int get () const { return hb_atomic_int_impl_get (&v); }
+ int get_acquire () const { return hb_atomic_int_impl_get (&v); }
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
@@ -167,11 +183,11 @@ struct hb_atomic_ptr_t
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
- T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
+ T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
- T * operator -> () const { return get (); }
- template <typename C> operator C * () const { return get (); }
+ T * operator -> () const { return get_acquire (); }
+ template <typename C> operator C * () const { return get_acquire (); }
T *v = nullptr;
};
diff --git a/src/hb-bimap.hh b/src/hb-bimap.hh
index d466af8b6..8e8c98871 100644
--- a/src/hb-bimap.hh
+++ b/src/hb-bimap.hh
@@ -33,26 +33,18 @@
/* Bi-directional map */
struct hb_bimap_t
{
- /* XXX(remove) */
- void init ()
- {
- forw_map.init ();
- back_map.init ();
- }
-
- /* XXX(remove) */
- void fini ()
- {
- forw_map.fini ();
- back_map.fini ();
- }
-
void reset ()
{
forw_map.reset ();
back_map.reset ();
}
+ void resize (unsigned pop)
+ {
+ forw_map.resize (pop);
+ back_map.resize (pop);
+ }
+
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
@@ -62,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)
{
@@ -86,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/src/hb-bit-page.hh b/src/hb-bit-page.hh
index 263be3d04..11987054f 100644
--- a/src/hb-bit-page.hh
+++ b/src/hb-bit-page.hh
@@ -30,6 +30,53 @@
#include "hb.hh"
+
+/* Compiler-assisted vectorization. */
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
+ * basically a fixed-size bitset. */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+ elt_t& operator [] (unsigned int i) { return v[i]; }
+ const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+ void clear (unsigned char v = 0) { hb_memset (this, v, sizeof (*this)); }
+
+ template <typename Op>
+ hb_vector_size_t process (const Op& op) const
+ {
+ hb_vector_size_t r;
+ for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+ r.v[i] = op (v[i]);
+ return r;
+ }
+ template <typename Op>
+ hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+ {
+ hb_vector_size_t r;
+ for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+ r.v[i] = op (v[i], o.v[i]);
+ return r;
+ }
+ hb_vector_size_t operator | (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_or, o); }
+ hb_vector_size_t operator & (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_and, o); }
+ hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+ { return process (hb_bitwise_xor, o); }
+ hb_vector_size_t operator ~ () const
+ { return process (hb_bitwise_neg); }
+
+ hb_array_t<const elt_t> iter () const
+ { return hb_array (v); }
+
+ private:
+ static_assert (0 == byte_size % sizeof (elt_t), "");
+ elt_t v[byte_size / sizeof (elt_t)];
+};
+
+
struct hb_bit_page_t
{
void init0 () { v.clear (); }
@@ -40,15 +87,22 @@ struct hb_bit_page_t
bool is_empty () const
{
- for (unsigned int i = 0; i < len (); i++)
- if (v[i])
- return false;
- return true;
+ return
+ + hb_iter (v)
+ | hb_none
+ ;
+ }
+ uint32_t hash () const
+ {
+ return
+ + hb_iter (v)
+ | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u)
+ ;
}
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
- void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+ void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
@@ -62,7 +116,7 @@ struct hb_bit_page_t
*la |= ~(mask (a) - 1);
la++;
- memset (la, 0xff, (char *) lb - (char *) la);
+ hb_memset (la, 0xff, (char *) lb - (char *) la);
*lb |= ((mask (b) << 1) - 1);
}
@@ -78,7 +132,7 @@ struct hb_bit_page_t
*la &= mask (a) - 1;
la++;
- memset (la, 0, (char *) lb - (char *) la);
+ hb_memset (la, 0, (char *) lb - (char *) la);
*lb &= ~((mask (b) << 1) - 1);
}
@@ -86,9 +140,78 @@ struct hb_bit_page_t
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
+
+ // Writes out page values to the array p. Returns the number of values
+ // written. At most size codepoints will be written.
+ unsigned int write (uint32_t base,
+ unsigned int start_value,
+ hb_codepoint_t *p,
+ unsigned int size) const
+ {
+ unsigned int start_v = start_value / ELT_BITS;
+ unsigned int start_bit = start_value & ELT_MASK;
+ unsigned int count = 0;
+ for (unsigned i = start_v; i < len () && count < size; i++)
+ {
+ elt_t bits = v[i];
+ uint32_t v_base = base | (i * ELT_BITS);
+ for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+ {
+ if ((elt_t(1) << j) & bits) {
+ *p++ = v_base | j;
+ count++;
+ }
+ }
+ start_bit = 0;
+ }
+ return count;
+ }
+
+ // Writes out the values NOT in this page to the array p. Returns the
+ // number of values written. At most size codepoints will be written.
+ // Returns the number of codepoints written. next_value holds the next value
+ // that should be written (if not present in this page). This is used to fill
+ // any missing value gaps between this page and the previous page, if any.
+ // next_value is updated to one more than the last value present in this page.
+ unsigned int write_inverted (uint32_t base,
+ unsigned int start_value,
+ hb_codepoint_t *p,
+ unsigned int size,
+ hb_codepoint_t *next_value) const
+ {
+ unsigned int start_v = start_value / ELT_BITS;
+ unsigned int start_bit = start_value & ELT_MASK;
+ unsigned int count = 0;
+ for (unsigned i = start_v; i < len () && count < size; i++)
+ {
+ elt_t bits = v[i];
+ uint32_t v_offset = i * ELT_BITS;
+ for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+ {
+ if ((elt_t(1) << j) & bits)
+ {
+ hb_codepoint_t value = base | v_offset | j;
+ // Emit all the missing values from next_value up to value - 1.
+ for (hb_codepoint_t k = *next_value; k < value && count < size; k++)
+ {
+ *p++ = k;
+ count++;
+ }
+ // Skip over this value;
+ *next_value = value + 1;
+ }
+ }
+ start_bit = 0;
+ }
+ return count;
+ }
+
bool is_equal (const hb_bit_page_t &other) const
{
- return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+ for (unsigned i = 0; i < len (); i++)
+ if (v[i] != other.v[i])
+ return false;
+ return true;
}
bool is_subset (const hb_bit_page_t &larger_page) const
{
@@ -100,10 +223,10 @@ struct hb_bit_page_t
unsigned int get_population () const
{
- unsigned int pop = 0;
- for (unsigned int i = 0; i < len (); i++)
- pop += hb_popcount (v[i]);
- return pop;
+ return
+ + hb_iter (v)
+ | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
+ ;
}
bool next (hb_codepoint_t *codepoint) const
@@ -179,6 +302,9 @@ struct hb_bit_page_t
typedef unsigned long long elt_t;
static constexpr unsigned PAGE_BITS = 512;
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+ static constexpr unsigned PAGE_BITS_LOG_2 = 9;
+ static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
+ static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
@@ -187,6 +313,7 @@ struct hb_bit_page_t
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+
static constexpr unsigned BITS = sizeof (vector_t) * 8;
static constexpr unsigned MASK = BITS - 1;
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
diff --git a/src/hb-bit-set-invertible.hh b/src/hb-bit-set-invertible.hh
index 0832b0fc2..ff8aecc60 100644
--- a/src/hb-bit-set-invertible.hh
+++ b/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))
@@ -120,10 +123,8 @@ struct hb_bit_set_invertible_t
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@@ -323,6 +324,14 @@ struct hb_bit_set_invertible_t
return true;
}
+ unsigned int next_many (hb_codepoint_t codepoint,
+ hb_codepoint_t *out,
+ unsigned int size) const
+ {
+ return inverted ? s.next_many_inverted (codepoint, out, size)
+ : s.next_many (codepoint, out, size);
+ }
+
static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
/*
diff --git a/src/hb-bit-set.hh b/src/hb-bit-set.hh
index a471ee48b..8de6e037f 100644
--- a/src/hb-bit-set.hh
+++ b/src/hb-bit-set.hh
@@ -78,17 +78,17 @@ 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;
void err () { if (successful) successful = false; } /* TODO Remove */
bool in_error () const { return !successful; }
- bool resize (unsigned int count)
+ bool resize (unsigned int count, bool clear = true)
{
if (unlikely (!successful)) return false;
- if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+ if (unlikely (!pages.resize (count, clear) || !page_map.resize (count, clear)))
{
pages.resize (page_map.length);
successful = false;
@@ -97,6 +97,13 @@ struct hb_bit_set_t
return true;
}
+ void alloc (unsigned sz)
+ {
+ sz >>= (page_t::PAGE_BITS_LOG_2 - 1);
+ pages.alloc (sz);
+ page_map.alloc (sz);
+ }
+
void reset ()
{
successful = true;
@@ -119,6 +126,14 @@ struct hb_bit_set_t
}
explicit operator bool () const { return !is_empty (); }
+ uint32_t hash () const
+ {
+ uint32_t h = 0;
+ for (auto &map : page_map)
+ h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]);
+ return h;
+ }
+
private:
void dirty () { population = UINT_MAX; }
public:
@@ -203,7 +218,7 @@ struct hb_bit_set_t
bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
- if (!count) return true;
+ if (unlikely (!count)) return true;
dirty ();
hb_codepoint_t g = *array;
hb_codepoint_t last_g = g;
@@ -222,7 +237,7 @@ struct hb_bit_set_t
if (v || page) /* The v check is to optimize out the page check if v is true. */
page->add (g);
- array = (const T *) ((const char *) array + stride);
+ array = &StructAtOffsetUnaligned<T> (array, stride);
count--;
}
while (count && (g = *array, g < end));
@@ -315,10 +330,8 @@ struct hb_bit_set_t
}
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@@ -337,19 +350,18 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return;
unsigned int count = other.pages.length;
- if (unlikely (!resize (count)))
+ if (unlikely (!resize (count, false)))
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 +389,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;
@@ -451,12 +463,10 @@ struct hb_bit_set_t
}
public:
- template <typename Op>
- void process (const Op& op, const hb_bit_set_t &other)
+ void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
+ bool passthru_left, bool passthru_right,
+ const hb_bit_set_t &other)
{
- const bool passthru_left = op (1, 0);
- const bool passthru_right = op (0, 1);
-
if (unlikely (!successful)) return;
dirty ();
@@ -528,21 +538,21 @@ struct hb_bit_set_t
b = nb;
for (; a && b; )
{
- if (page_map[a - 1].major == other.page_map[b - 1].major)
+ if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major)
{
a--;
b--;
count--;
- page_map[count] = page_map[a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
page_at (count).v = op (page_at (a).v, other.page_at (b).v);
}
- else if (page_map[a - 1].major > other.page_map[b - 1].major)
+ else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
{
a--;
if (passthru_left)
{
count--;
- page_map[count] = page_map[a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
}
}
else
@@ -551,8 +561,8 @@ struct hb_bit_set_t
if (passthru_right)
{
count--;
- page_map[count].major = other.page_map[b].major;
- page_map[count].index = next_page++;
+ page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+ page_map.arrayZ[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
}
@@ -562,20 +572,29 @@ struct hb_bit_set_t
{
a--;
count--;
- page_map[count] = page_map [a];
+ page_map.arrayZ[count] = page_map.arrayZ[a];
}
if (passthru_right)
while (b)
{
b--;
count--;
- page_map[count].major = other.page_map[b].major;
- page_map[count].index = next_page++;
+ page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+ page_map.arrayZ[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
assert (!count);
resize (newCount);
}
+ template <typename Op>
+ static hb_bit_page_t::vector_t
+ op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
+ { return Op{} (a, b); }
+ template <typename Op>
+ void process (const Op& op, const hb_bit_set_t &other)
+ {
+ process_ (op_<Op>, op (1, 0), op (0, 1), other);
+ }
void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
@@ -584,8 +603,6 @@ struct hb_bit_set_t
bool next (hb_codepoint_t *codepoint) const
{
- // TODO: this should be merged with prev() as both implementations
- // are very similar.
if (unlikely (*codepoint == INVALID)) {
*codepoint = get_min ();
return *codepoint != INVALID;
@@ -619,7 +636,7 @@ struct hb_bit_set_t
for (; i < page_map.length; i++)
{
- const page_map_t &current = page_map.arrayZ[i];
+ const page_map_t &current = page_map_array[i];
hb_codepoint_t m = pages_array[current.index].get_min ();
if (m != INVALID)
{
@@ -642,21 +659,21 @@ struct hb_bit_set_t
page_map_t map = {get_major (*codepoint), 0};
unsigned int i;
page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
- if (i < page_map.length && page_map[i].major == map.major)
+ if (i < page_map.length && page_map.arrayZ[i].major == map.major)
{
- if (pages[page_map[i].index].previous (codepoint))
+ if (pages[page_map.arrayZ[i].index].previous (codepoint))
{
- *codepoint += page_map[i].major * page_t::PAGE_BITS;
+ *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS;
return true;
}
}
i--;
for (; (int) i >= 0; i--)
{
- hb_codepoint_t m = pages[page_map[i].index].get_max ();
+ hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max ();
if (m != INVALID)
{
- *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+ *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m;
return true;
}
}
@@ -700,6 +717,99 @@ struct hb_bit_set_t
return true;
}
+ unsigned int next_many (hb_codepoint_t codepoint,
+ hb_codepoint_t *out,
+ unsigned int size) const
+ {
+ // By default, start at the first bit of the first page of values.
+ unsigned int start_page = 0;
+ unsigned int start_page_value = 0;
+ if (unlikely (codepoint != INVALID))
+ {
+ const auto* page_map_array = page_map.arrayZ;
+ unsigned int major = get_major (codepoint);
+ unsigned int i = last_page_lookup;
+ if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+ {
+ page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+ if (i >= page_map.length)
+ return 0; // codepoint is greater than our max element.
+ }
+ start_page = i;
+ start_page_value = page_remainder (codepoint + 1);
+ if (unlikely (start_page_value == 0))
+ {
+ // The export-after value was last in the page. Start on next page.
+ start_page++;
+ start_page_value = 0;
+ }
+ }
+
+ unsigned int initial_size = size;
+ for (unsigned int i = start_page; i < page_map.length && size; i++)
+ {
+ uint32_t base = major_start (page_map[i].major);
+ unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
+ out += n;
+ size -= n;
+ start_page_value = 0;
+ }
+ return initial_size - size;
+ }
+
+ unsigned int next_many_inverted (hb_codepoint_t codepoint,
+ hb_codepoint_t *out,
+ unsigned int size) const
+ {
+ unsigned int initial_size = size;
+ // By default, start at the first bit of the first page of values.
+ unsigned int start_page = 0;
+ unsigned int start_page_value = 0;
+ if (unlikely (codepoint != INVALID))
+ {
+ const auto* page_map_array = page_map.arrayZ;
+ unsigned int major = get_major (codepoint);
+ unsigned int i = last_page_lookup;
+ if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+ {
+ page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+ if (unlikely (i >= page_map.length))
+ {
+ // codepoint is greater than our max element.
+ while (++codepoint != INVALID && size)
+ {
+ *out++ = codepoint;
+ size--;
+ }
+ return initial_size - size;
+ }
+ }
+ start_page = i;
+ start_page_value = page_remainder (codepoint + 1);
+ if (unlikely (start_page_value == 0))
+ {
+ // The export-after value was last in the page. Start on next page.
+ start_page++;
+ start_page_value = 0;
+ }
+ }
+
+ hb_codepoint_t next_value = codepoint + 1;
+ for (unsigned int i=start_page; i<page_map.length && size; i++)
+ {
+ uint32_t base = major_start (page_map[i].major);
+ unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
+ out += n;
+ size -= n;
+ start_page_value = 0;
+ }
+ while (next_value < HB_SET_VALUE_INVALID && size) {
+ *out++ = next_value++;
+ size--;
+ }
+ return initial_size - size;
+ }
+
bool has_population () const { return population != UINT_MAX; }
unsigned int get_population () const
{
@@ -781,8 +891,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;
+ if (likely (i < page_map.length))
+ {
+ auto &cached_page = page_map.arrayZ[i];
+ if (cached_page.major == major)
+ return &pages.arrayZ[cached_page.index];
+ }
+
+ page_map_t map = {major, pages.length};
if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
{
if (!insert)
@@ -791,26 +913,51 @@ struct hb_bit_set_t
if (unlikely (!resize (pages.length + 1)))
return nullptr;
- pages[map.index].init0 ();
- memmove (page_map + i + 1,
- page_map + i,
+ pages.arrayZ[map.index].init0 ();
+ memmove (page_map.arrayZ + i + 1,
+ page_map.arrayZ + i,
(page_map.length - 1 - i) * page_map.item_size);
page_map[i] = map;
}
- return &pages[page_map[i].index];
+
+ last_page_lookup = i;
+ return &pages.arrayZ[page_map.arrayZ[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;
+ if (likely (i < page_map.length))
+ {
+ auto &cached_page = page_map.arrayZ[i];
+ if (cached_page.major == major)
+ return &pages.arrayZ[cached_page.index];
+ }
+
+ page_map_t key = {major};
+ if (!page_map.bfind (key, &i))
+ return nullptr;
+
+ last_page_lookup = i;
+ return &pages.arrayZ[page_map[i].index];
+ }
+ page_t &page_at (unsigned int i)
+ {
+ assert (i < page_map.length);
+ return pages.arrayZ[page_map.arrayZ[i].index];
+ }
+ const page_t &page_at (unsigned int i) const
+ {
+ assert (i < page_map.length);
+ return pages.arrayZ[page_map.arrayZ[i].index];
}
- page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
- const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
- unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
- hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
+ unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
+ unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
+ hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
};
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index f120002d1..f0fda1fa4 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -99,7 +99,7 @@ hb_blob_create (const char *data,
* is zero. This is in contrast to hb_blob_create(), which returns the singleton
* empty blob (as returned by hb_blob_get_empty()) if @length is zero.
*
- * Return value: New blob, or %NULL if failed. Destroy with hb_blob_destroy().
+ * Return value: New blob, or `NULL` if failed. Destroy with hb_blob_destroy().
*
* Since: 2.8.2
**/
@@ -263,8 +263,6 @@ hb_blob_destroy (hb_blob_t *blob)
{
if (!hb_object_destroy (blob)) return;
- blob->fini_shallow ();
-
hb_free (blob);
}
@@ -278,7 +276,7 @@ hb_blob_destroy (hb_blob_t *blob)
*
* Attaches a user-data key/data pair to the specified blob.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -305,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
* Since: 0.9.2
**/
void *
-hb_blob_get_user_data (hb_blob_t *blob,
+hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (blob, key);
@@ -335,7 +333,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
*
* Tests whether a blob is immutable.
*
- * Return value: %true if @blob is immutable, %false otherwise
+ * Return value: `true` if @blob is immutable, `false` otherwise
*
* Since: 0.9.2
**/
@@ -369,7 +367,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
**/
@@ -394,7 +392,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
* fails.
*
* Returns: (transfer none) (array length=length): Writable blob data,
- * or %NULL if failed.
+ * or `NULL` if failed.
*
* Since: 0.9.2
**/
@@ -497,7 +495,7 @@ hb_blob_t::try_make_writable ()
DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
- memcpy (new_data, this->data, this->length);
+ hb_memcpy (new_data, this->data, this->length);
this->destroy_user_data ();
this->mode = HB_MEMORY_MODE_WRITABLE;
this->data = new_data;
@@ -572,7 +570,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);
@@ -620,7 +618,7 @@ hb_blob_create_from_file (const char *file_name)
* specified binary font file.
*
* Returns: An #hb_blob_t pointer with the content of the file,
- * or %NULL if failed.
+ * or `NULL` if failed.
*
* Since: 2.8.2
**/
@@ -631,7 +629,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 +669,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/src/hb-blob.h b/src/hb-blob.h
index 203f9e19d..4eb42314d 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
HB_EXTERN void *
-hb_blob_get_user_data (hb_blob_t *blob,
+hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key);
diff --git a/src/hb-blob.hh b/src/hb-blob.hh
index a3683a681..b1b3b94d3 100644
--- a/src/hb-blob.hh
+++ b/src/hb-blob.hh
@@ -38,7 +38,7 @@
struct hb_blob_t
{
- void fini_shallow () { destroy_user_data (); }
+ ~hb_blob_t () { destroy_user_data (); }
void destroy_user_data ()
{
@@ -61,12 +61,12 @@ struct hb_blob_t
public:
hb_object_header_t header;
- const char *data;
- unsigned int length;
- hb_memory_mode_t mode;
+ const char *data = nullptr;
+ unsigned int length = 0;
+ hb_memory_mode_t mode = (hb_memory_mode_t) 0;
- void *user_data;
- hb_destroy_func_t destroy;
+ void *user_data = nullptr;
+ hb_destroy_func_t destroy = nullptr;
};
diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh
index e80cfea6e..993bb1f69 100644
--- a/src/hb-buffer-deserialize-json.hh
+++ b/src/hb-buffer-deserialize-json.hh
@@ -32,15 +32,16 @@
#include "hb.hh"
-#line 36 "hb-buffer-deserialize-json.hh"
+#line 33 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
- 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
- 34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
- 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+ 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u,
+ 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u,
+ 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u,
+ 9u, 123u, 0u, 0u, 0
};
static const char _deserialize_json_key_spans[] = {
@@ -48,9 +49,10 @@ static const char _deserialize_json_key_spans[] = {
10, 117, 117, 117, 1, 50, 49, 10,
117, 117, 1, 1, 50, 49, 117, 117,
2, 1, 50, 49, 10, 117, 117, 1,
- 50, 49, 10, 117, 117, 1, 50, 49,
- 59, 117, 59, 117, 117, 1, 50, 49,
- 117, 85, 115, 0
+ 50, 49, 10, 117, 117, 1, 1, 50,
+ 49, 117, 117, 1, 50, 49, 59, 117,
+ 59, 117, 117, 1, 50, 49, 117, 85,
+ 115, 0
};
static const short _deserialize_json_index_offsets[] = {
@@ -58,9 +60,10 @@ static const short _deserialize_json_index_offsets[] = {
271, 282, 400, 518, 636, 638, 689, 739,
750, 868, 986, 988, 990, 1041, 1091, 1209,
1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680,
- 1682, 1733, 1783, 1794, 1912, 2030, 2032, 2083,
- 2133, 2193, 2311, 2371, 2489, 2607, 2609, 2660,
- 2710, 2828, 2914, 3030
+ 1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034,
+ 2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534,
+ 2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169,
+ 3255, 3371
};
static const char _deserialize_json_indicies[] = {
@@ -82,28 +85,28 @@ static const char _deserialize_json_indicies[] = {
3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 4, 1,
- 5, 1, 6, 7, 1, 1, 8, 1,
+ 5, 1, 6, 7, 1, 8, 9, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 9, 1, 10, 11,
- 1, 12, 1, 12, 12, 12, 12, 12,
+ 1, 1, 1, 1, 10, 1, 11, 12,
+ 1, 13, 1, 13, 13, 13, 13, 13,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 12, 1, 1, 1, 1, 1,
+ 1, 1, 13, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 13, 1, 13, 13,
- 13, 13, 13, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 14, 1, 14, 14,
+ 14, 14, 14, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 13, 1, 1,
+ 1, 1, 1, 1, 1, 14, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 14, 1, 1, 15, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 1,
- 17, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 1, 19, 19, 19, 19, 19,
+ 1, 1, 15, 1, 1, 16, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 1,
+ 18, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 1, 20, 20, 20, 20, 20,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 19, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 20, 1,
+ 1, 1, 20, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 21, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -113,11 +116,11 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 21,
- 1, 22, 22, 22, 22, 22, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 22,
+ 1, 23, 23, 23, 23, 23, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 22, 1, 1, 1, 1, 1, 1, 1,
+ 23, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -128,41 +131,58 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 23, 1, 19,
- 19, 19, 19, 19, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 24, 1, 20,
+ 20, 20, 20, 20, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 20, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 21, 1, 1, 1, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 22, 1, 25, 1, 25,
+ 25, 25, 25, 25, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 25, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 19, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 20, 1, 1, 1, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18,
+ 26, 1, 26, 26, 26, 26, 26, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 26, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 27, 1,
+ 1, 28, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 1, 30, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 1, 32,
+ 32, 32, 32, 32, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 32, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 33, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 21, 1, 24, 1, 24,
- 24, 24, 24, 24, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 24, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 25, 1, 25, 25, 25, 25, 25, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 34, 1, 32, 32, 32,
+ 32, 32, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 25, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 26, 1,
- 1, 27, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 1, 29, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 1, 31,
- 31, 31, 31, 31, 1, 1, 1, 1,
+ 1, 1, 1, 1, 32, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 31, 1,
+ 33, 1, 1, 1, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 32, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -170,41 +190,41 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 34, 1, 35, 1, 36, 1, 36,
+ 36, 36, 36, 36, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 36, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 33, 1, 31, 31, 31,
- 31, 31, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 31, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 32, 1, 1, 1, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 1, 1,
+ 37, 1, 37, 37, 37, 37, 37, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 37, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 38, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 1, 40, 40, 40, 40,
+ 40, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 40, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 41,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 33, 1, 34, 1, 35, 1, 35,
- 35, 35, 35, 35, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 35, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 36, 1, 36, 36, 36, 36, 36, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 36, 1, 1, 1, 1, 1, 1,
+ 42, 1, 40, 40, 40, 40, 40, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 37, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 1, 39, 39, 39, 39,
- 39, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 39, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 40,
+ 1, 40, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 41, 1, 1,
+ 1, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -212,137 +232,130 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 42, 1,
+ 44, 45, 1, 46, 1, 46, 46, 46,
+ 46, 46, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 46, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 41, 1, 39, 39, 39, 39, 39, 1,
+ 1, 1, 1, 1, 1, 1, 47, 1,
+ 47, 47, 47, 47, 47, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 47,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 39, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 40, 1, 1,
- 1, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 48, 1, 1, 49,
+ 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 1, 51, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 1, 53, 53, 53,
+ 53, 53, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 53, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 54, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 41, 1,
- 43, 44, 1, 45, 1, 45, 45, 45,
- 45, 45, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 45, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 46, 1,
- 46, 46, 46, 46, 46, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 46,
+ 1, 55, 1, 53, 53, 53, 53, 53,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 47, 1, 1, 48,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 1, 50, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 1, 52, 52, 52,
- 52, 52, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 52, 1, 1, 1,
+ 1, 1, 53, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 54, 1,
+ 1, 1, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 53, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 55,
+ 1, 56, 1, 56, 56, 56, 56, 56,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 56, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 54, 1, 52, 52, 52, 52, 52,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 57, 1, 57, 57,
+ 57, 57, 57, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 52, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 53, 1,
- 1, 1, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 57, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 58, 1, 1, 59, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 1,
+ 61, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 1, 63, 63, 63, 63, 63,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 63, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 64, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 54,
- 1, 55, 1, 55, 55, 55, 55, 55,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 55, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 56, 1, 56, 56,
- 56, 56, 56, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 56, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 65,
+ 1, 63, 63, 63, 63, 63, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 57, 1, 1, 58, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 1,
- 60, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 1, 62, 62, 62, 62, 62,
1, 1, 1, 1, 1, 1, 1, 1,
+ 63, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 64, 1, 1, 1,
+ 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 62, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 63, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 65, 1, 66,
+ 1, 67, 1, 67, 67, 67, 67, 67,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 67, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 64,
- 1, 62, 62, 62, 62, 62, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 68, 1, 68, 68,
+ 68, 68, 68, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 62, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 63, 1, 1, 1,
- 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 68, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 69, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 1,
+ 71, 71, 71, 71, 71, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 71,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 72, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 64, 1, 65,
- 1, 65, 65, 65, 65, 65, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 65, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 66, 1, 66, 66, 66, 66,
- 66, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 66, 1, 67, 1, 1,
+ 1, 1, 1, 1, 73, 1, 71, 71,
+ 71, 71, 71, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 68, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 1, 71, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,
- 72, 70, 73, 73, 73, 73, 73, 1,
+ 1, 1, 1, 1, 1, 71, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 72, 1, 1, 1, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 73, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 74, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -350,21 +363,33 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 73, 1, 75, 1, 75, 75,
+ 75, 75, 75, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 75, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 75, 1,
- 70, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 76,
+ 1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 76, 1, 77, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 78, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 1, 81, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 82, 80, 83,
+ 83, 83, 83, 83, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 83, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 70, 1, 76, 76, 76, 76,
- 76, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 84, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 76, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 77,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -373,67 +398,85 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 85, 1, 80, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 78, 1, 76, 76, 76, 76, 76, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 76, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 77, 1, 1,
- 1, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 79, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 80,
+ 1, 86, 86, 86, 86, 86, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 86, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 87, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 78, 1,
- 80, 1, 80, 80, 80, 80, 80, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 80, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 88, 1, 86,
+ 86, 86, 86, 86, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 81, 1, 81, 81, 81,
- 81, 81, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 86, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 81, 1, 1, 1,
+ 1, 1, 87, 1, 1, 1, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 82, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 1, 76,
- 76, 76, 76, 76, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 76, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 77, 1, 1, 1, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 88, 1, 90, 1, 90,
+ 90, 90, 90, 90, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 90, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 78, 1, 85, 85, 85,
- 85, 85, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 85, 1, 1, 1,
+ 91, 1, 91, 91, 91, 91, 91, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 91, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 92, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 1, 86, 86, 86, 86,
86, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 86, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 87,
+ 1, 1, 1, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 88, 1, 95, 95, 95, 95, 95, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 95, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 96, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 87, 1, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 97, 1,
+ 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -442,46 +485,52 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 2, 1, 1,
- 0
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 1, 1, 0
};
static const char _deserialize_json_trans_targs[] = {
1, 0, 2, 2, 3, 4, 18, 24,
- 37, 45, 5, 12, 6, 7, 8, 9,
- 11, 9, 11, 10, 2, 49, 10, 49,
- 13, 14, 15, 16, 17, 16, 17, 10,
- 2, 49, 19, 20, 21, 22, 23, 10,
- 2, 49, 23, 25, 31, 26, 27, 28,
- 29, 30, 29, 30, 10, 2, 49, 32,
- 33, 34, 35, 36, 35, 36, 10, 2,
- 49, 38, 39, 40, 43, 44, 40, 41,
- 42, 10, 2, 49, 10, 2, 49, 44,
- 46, 47, 43, 48, 48, 49, 50, 51
+ 37, 43, 51, 5, 12, 6, 7, 8,
+ 9, 11, 9, 11, 10, 2, 55, 10,
+ 55, 13, 14, 15, 16, 17, 16, 17,
+ 10, 2, 55, 19, 20, 21, 22, 23,
+ 10, 2, 55, 23, 25, 31, 26, 27,
+ 28, 29, 30, 29, 30, 10, 2, 55,
+ 32, 33, 34, 35, 36, 35, 36, 10,
+ 2, 55, 38, 39, 40, 41, 42, 10,
+ 2, 55, 42, 44, 45, 46, 49, 50,
+ 46, 47, 48, 10, 2, 55, 10, 2,
+ 55, 50, 52, 53, 49, 54, 54, 55,
+ 56, 57
};
static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 0, 0, 3, 3, 4, 0, 5,
- 0, 0, 2, 2, 2, 0, 0, 6,
- 6, 7, 0, 0, 0, 2, 2, 8,
- 8, 9, 0, 0, 0, 0, 0, 2,
- 2, 2, 0, 0, 10, 10, 11, 0,
- 0, 2, 2, 2, 0, 0, 12, 12,
- 13, 0, 0, 2, 14, 14, 0, 15,
- 0, 16, 16, 17, 18, 18, 19, 15,
- 0, 0, 20, 20, 21, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 2, 2, 0, 0, 3, 3, 4, 0,
+ 5, 0, 0, 2, 2, 2, 0, 0,
+ 6, 6, 7, 0, 0, 0, 2, 2,
+ 8, 8, 9, 0, 0, 0, 0, 0,
+ 2, 2, 2, 0, 0, 10, 10, 11,
+ 0, 0, 2, 2, 2, 0, 0, 12,
+ 12, 13, 0, 0, 0, 2, 2, 14,
+ 14, 15, 0, 0, 0, 2, 16, 16,
+ 0, 17, 0, 18, 18, 19, 20, 20,
+ 21, 17, 0, 0, 22, 22, 23, 0,
+ 0, 0
};
static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 49;
+static const int deserialize_json_first_final = 55;
static const int deserialize_json_error = 0;
static const int deserialize_json_en_main = 1;
-#line 108 "hb-buffer-deserialize-json.rl"
+#line 111 "hb-buffer-deserialize-json.rl"
static hb_bool_t
@@ -508,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 512 "hb-buffer-deserialize-json.hh"
+#line 554 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
-#line 517 "hb-buffer-deserialize-json.hh"
+#line 557 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@@ -541,8 +590,8 @@ _resume:
case 1:
#line 38 "hb-buffer-deserialize-json.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
break;
case 5:
@@ -561,25 +610,25 @@ _resume:
tok = p;
}
break;
- case 15:
+ case 17:
#line 55 "hb-buffer-deserialize-json.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
- case 21:
+ case 23:
#line 56 "hb-buffer-deserialize-json.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
- case 16:
+ case 18:
#line 58 "hb-buffer-deserialize-json.rl"
{
/* TODO Unescape \" and \\ if found. */
if (!hb_font_glyph_from_string (font,
- tok, p - tok,
+ tok+1, p - tok - 2, /* Skip "" */
&info.codepoint))
return false;
}
break;
- case 18:
+ case 20:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
break;
@@ -604,6 +653,10 @@ _resume:
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
case 14:
+#line 72 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.mask )) return false; }
+ break;
+ case 16:
#line 51 "hb-buffer-deserialize-json.rl"
{
tok = p;
@@ -611,7 +664,7 @@ _resume:
#line 55 "hb-buffer-deserialize-json.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
- case 20:
+ case 22:
#line 51 "hb-buffer-deserialize-json.rl"
{
tok = p;
@@ -619,12 +672,12 @@ _resume:
#line 56 "hb-buffer-deserialize-json.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
- case 17:
+ case 19:
#line 58 "hb-buffer-deserialize-json.rl"
{
/* TODO Unescape \" and \\ if found. */
if (!hb_font_glyph_from_string (font,
- tok, p - tok,
+ tok+1, p - tok - 2, /* Skip "" */
&info.codepoint))
return false;
}
@@ -637,7 +690,7 @@ _resume:
*end_ptr = p;
}
break;
- case 19:
+ case 21:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
@@ -709,7 +762,19 @@ _resume:
*end_ptr = p;
}
break;
-#line 713 "hb-buffer-deserialize-json.hh"
+ case 15:
+#line 72 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.mask )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (unlikely (!buffer->successful))
+ return false;
+ buffer->pos[buffer->len - 1] = pos;
+ *end_ptr = p;
+}
+ break;
+#line 735 "hb-buffer-deserialize-json.hh"
}
_again:
@@ -721,7 +786,7 @@ _again:
_out: {}
}
-#line 136 "hb-buffer-deserialize-json.rl"
+#line 139 "hb-buffer-deserialize-json.rl"
*end_ptr = p;
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
index 382423f6c..d6fbfe89c 100644
--- a/src/hb-buffer-deserialize-json.rl
+++ b/src/hb-buffer-deserialize-json.rl
@@ -36,8 +36,8 @@ alphtype unsigned char;
write data;
action clear_item {
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
action add_item {
@@ -58,17 +58,18 @@ action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false;
action parse_glyph_name {
/* TODO Unescape \" and \\ if found. */
if (!hb_font_glyph_from_string (font,
- tok, p - tok,
+ tok+1, p - tok - 2, /* Skip "" */
&info.codepoint))
return false;
}
-action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; }
-action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask )) return false; }
unum = '0' | [1-9] digit*;
num = '-'? unum;
@@ -82,13 +83,14 @@ glyph_name = '"' ([^\\"] | '\\' [\\"])* '"';
parse_glyph_name = (glyph_name >tok %parse_glyph_name);
parse_codepoint = (codepoint >tok %parse_codepoint);
-glyph = "\"g\"" colon (parse_glyph_name | parse_codepoint);
-unicode = "\"u\"" colon parse_codepoint;
-cluster = "\"cl\"" colon (unum >tok %parse_cluster);
-xoffset = "\"dx\"" colon (num >tok %parse_x_offset);
-yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
-xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
-yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+glyph = "\"g\"" colon (parse_glyph_name | parse_codepoint);
+unicode = "\"u\"" colon parse_codepoint;
+cluster = "\"cl\"" colon (unum >tok %parse_cluster);
+xoffset = "\"dx\"" colon (num >tok %parse_x_offset);
+yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
+xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
+yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
element = glyph @ensure_glyphs
| unicode @ensure_unicode
@@ -96,7 +98,8 @@ element = glyph @ensure_glyphs
| xoffset
| yoffset
| xadvance
- | yadvance;
+ | yadvance
+ | glyphflags;
item =
( '{' space* element (comma element)* space* '}')
>clear_item
diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh
index b599e9667..6b9b4282f 100644
--- a/src/hb-buffer-deserialize-text.hh
+++ b/src/hb-buffer-deserialize-text.hh
@@ -32,29 +32,30 @@
#include "hb.hh"
-#line 36 "hb-buffer-deserialize-text.hh"
+#line 33 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
- 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u,
- 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u,
- 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 9u, 124u,
+ 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 48u, 57u,
+ 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u,
+ 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
- 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 0
+ 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
+ 0
};
static const char _deserialize_text_key_spans[] = {
- 0, 83, 1, 1, 55, 77, 10, 13,
- 10, 10, 13, 10, 1, 13, 10, 14,
- 82, 13, 10, 116, 116, 0, 77, 116,
+ 0, 83, 1, 1, 55, 77, 10, 10,
+ 13, 10, 13, 10, 10, 13, 10, 1,
+ 13, 10, 14, 82, 116, 116, 0, 77,
116, 116, 116, 116, 116, 116, 116, 116,
- 116, 116, 116, 116, 116
+ 116, 116, 116, 116, 116, 116, 116, 116
};
static const short _deserialize_text_index_offsets[] = {
0, 0, 84, 86, 88, 144, 222, 233,
- 247, 258, 269, 283, 294, 296, 310, 321,
- 336, 419, 433, 444, 561, 678, 679, 757,
- 874, 991, 1108, 1225, 1342, 1459, 1576, 1693,
- 1810, 1927, 2044, 2161, 2278
+ 244, 258, 269, 283, 294, 305, 319, 330,
+ 332, 346, 357, 372, 455, 572, 689, 690,
+ 768, 885, 1002, 1119, 1236, 1353, 1470, 1587,
+ 1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523
};
static const char _deserialize_text_indicies[] = {
@@ -87,210 +88,226 @@ static const char _deserialize_text_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 1, 8,
9, 9, 9, 9, 9, 9, 9, 9,
- 9, 1, 10, 1, 1, 11, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 1,
+ 9, 1, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 1, 12, 1, 1,
13, 14, 14, 14, 14, 14, 14, 14,
14, 14, 1, 15, 16, 16, 16, 16,
16, 16, 16, 16, 16, 1, 17, 1,
1, 18, 19, 19, 19, 19, 19, 19,
19, 19, 19, 1, 20, 21, 21, 21,
21, 21, 21, 21, 21, 21, 1, 22,
- 1, 23, 1, 1, 24, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 1, 26,
- 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 1, 22, 1, 1, 1, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21,
- 1, 28, 28, 1, 1, 1, 1, 1,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 1, 24, 1, 1, 25, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 1,
+ 27, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 1, 29, 1, 30, 1, 1,
+ 31, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 1, 33, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 1, 29, 1,
+ 1, 1, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 1, 35, 35, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 35,
+ 1, 1, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 28, 1, 1, 28, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 35, 35,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 28, 28, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 35, 1,
+ 36, 36, 36, 36, 36, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 36,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 28, 1, 29, 1, 1, 30,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 1, 32, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 1, 34, 34, 34,
- 34, 34, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 1, 1, 1, 38, 39, 1, 1,
+ 37, 37, 37, 37, 37, 37, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 34, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 1, 1,
- 1, 36, 37, 1, 1, 35, 35, 35,
- 35, 35, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 37, 37, 37, 37, 37, 37, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 35, 35, 35,
- 35, 35, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 40, 1, 41, 41, 41,
+ 41, 41, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 38, 1, 39, 39, 39, 39, 39, 1,
+ 1, 1, 1, 1, 41, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 39, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 42, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 40,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 43, 1, 1, 7, 7, 7, 7, 7,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 41, 1, 1,
- 7, 7, 7, 7, 7, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 7,
+ 1, 1, 7, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 4,
+ 1, 44, 44, 44, 44, 44, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 4, 1, 42, 42,
- 42, 42, 42, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 42, 1, 1,
+ 44, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 43, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 46, 1, 44, 44,
+ 44, 44, 44, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 44, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 1,
+ 1, 1, 1, 45, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 44, 1, 42, 42, 42, 42, 42,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 42, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 1, 1, 1, 1,
- 43, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 46, 1, 49, 49, 49, 49, 49,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 49, 48, 48, 50, 48, 48,
+ 48, 48, 48, 48, 48, 51, 1, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 52,
+ 48, 48, 53, 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, 48, 48, 54, 55,
+ 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, 48, 48, 48, 48, 48, 56, 48,
+ 57, 57, 57, 57, 57, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 57,
+ 35, 35, 58, 35, 35, 35, 35, 35,
+ 35, 35, 59, 1, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 60, 35, 35, 61,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 62, 63, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 64, 35, 65, 65, 65,
+ 65, 65, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 65, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 44, 1,
- 47, 47, 47, 47, 47, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 47,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 48, 1, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 49, 46, 46, 50,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 51, 52, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 53, 46, 54, 54, 54,
- 54, 54, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 54, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 55,
- 1, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 56, 28, 28, 57, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 58, 59, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28,
- 60, 28, 61, 61, 61, 61, 61, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 61, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 62, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 66, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 67, 1, 68, 68, 68, 68, 68, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 63, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 68, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 64, 1, 65,
- 65, 65, 65, 65, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 65, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 42, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 69, 1, 70,
+ 70, 70, 70, 70, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 70, 48,
+ 48, 50, 48, 48, 48, 48, 48, 48,
+ 48, 51, 1, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 52, 48, 48, 53, 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,
+ 48, 48, 54, 55, 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, 48, 48, 48,
+ 48, 48, 56, 48, 71, 71, 71, 71,
+ 71, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 40, 1, 1, 1, 1,
+ 1, 1, 1, 71, 1, 1, 72, 1,
+ 1, 1, 1, 1, 1, 1, 1, 73,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 66, 1, 67, 67, 67, 67,
- 67, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 67, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 48, 1,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 49, 46, 46, 50, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 51,
- 52, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 53,
- 46, 68, 68, 68, 68, 68, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 68, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 69, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 74, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 70, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 75,
+ 1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 43, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 76, 1, 1, 77, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 71, 1, 72, 72,
- 72, 72, 72, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 72, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 73, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 78, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 74, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 79, 1, 76, 76,
+ 76, 76, 76, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 76, 1, 1,
+ 77, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 75, 1, 72, 72, 72, 72, 72,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 72, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 73, 1, 1,
- 1, 1, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 27, 1, 1, 1, 1,
+ 1, 1, 78, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 79, 1, 71, 71, 71, 71, 71,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 71, 1, 1, 72, 1, 1,
+ 1, 1, 1, 1, 1, 1, 73, 1,
+ 1, 1, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -299,109 +316,128 @@ static const char _deserialize_text_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 75, 1,
- 68, 68, 68, 68, 68, 1, 1, 1,
+ 80, 80, 80, 80, 80, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 80,
+ 1, 1, 81, 1, 1, 1, 1, 1,
+ 1, 1, 82, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 83,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 68,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 69, 1, 1, 1, 1, 76,
- 76, 76, 76, 76, 76, 76, 76, 76,
- 76, 1, 1, 1, 1, 1, 1, 70,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 45, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 43, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 84, 1, 85, 85, 85,
+ 85, 85, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 85, 1, 1, 86,
+ 1, 1, 1, 1, 1, 1, 1, 87,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 71, 1, 77, 77, 77,
- 77, 77, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 77, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 88, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 78, 1, 1, 1, 1, 1, 1,
+ 89, 1, 85, 85, 85, 85, 85, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 85, 1, 1, 86, 1, 1, 1,
+ 1, 1, 1, 1, 87, 1, 1, 1,
+ 1, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 79, 1, 77, 77, 77, 77, 77, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 77, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 88, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 89, 1, 80,
+ 80, 80, 80, 80, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 78, 1,
+ 1, 1, 1, 1, 1, 1, 80, 1,
+ 1, 81, 1, 1, 1, 1, 1, 1,
+ 1, 82, 1, 1, 1, 1, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90,
+ 1, 1, 1, 1, 1, 1, 83, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 79, 1, 61,
- 61, 61, 61, 61, 1, 1, 1, 1,
+ 1, 1, 1, 45, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 61, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 62, 1, 1, 1, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 84, 1, 65, 65, 65, 65,
+ 65, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 65, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 63, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 64, 1, 0
+ 66, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 67,
+ 1, 0
};
static const char _deserialize_text_trans_targs[] = {
- 1, 0, 2, 25, 3, 4, 19, 5,
- 23, 24, 8, 27, 36, 27, 36, 30,
- 33, 11, 12, 15, 12, 15, 13, 14,
- 31, 32, 31, 32, 26, 18, 34, 35,
- 34, 35, 20, 19, 6, 21, 22, 20,
- 21, 22, 20, 21, 22, 24, 26, 26,
- 7, 9, 10, 16, 21, 29, 26, 7,
- 9, 10, 16, 21, 29, 28, 17, 21,
- 29, 28, 29, 29, 28, 7, 10, 29,
- 28, 7, 21, 29, 33, 28, 21, 29
+ 1, 0, 2, 26, 3, 4, 20, 5,
+ 24, 25, 28, 39, 9, 31, 34, 31,
+ 34, 11, 32, 33, 32, 33, 35, 38,
+ 14, 15, 18, 15, 18, 16, 17, 36,
+ 37, 36, 37, 27, 21, 20, 6, 22,
+ 23, 21, 22, 23, 21, 22, 23, 25,
+ 27, 27, 7, 8, 12, 13, 19, 22,
+ 30, 27, 7, 8, 12, 13, 19, 22,
+ 30, 29, 22, 30, 29, 30, 30, 29,
+ 7, 10, 22, 30, 29, 7, 22, 30,
+ 29, 7, 8, 13, 30, 29, 7, 8,
+ 22, 30, 38, 39
};
static const char _deserialize_text_trans_actions[] = {
0, 0, 0, 0, 1, 0, 2, 0,
- 2, 2, 3, 4, 4, 5, 5, 4,
- 4, 3, 3, 3, 0, 0, 6, 3,
- 4, 4, 5, 5, 5, 3, 4, 4,
- 5, 5, 7, 8, 9, 7, 7, 0,
- 0, 0, 10, 10, 10, 8, 12, 13,
- 14, 14, 14, 15, 11, 11, 17, 18,
- 18, 18, 0, 16, 16, 19, 20, 19,
- 19, 0, 0, 13, 10, 21, 21, 10,
- 22, 23, 22, 22, 5, 24, 24, 24
+ 2, 2, 3, 3, 4, 3, 3, 5,
+ 5, 4, 3, 3, 5, 5, 3, 3,
+ 4, 4, 4, 0, 0, 6, 4, 3,
+ 3, 5, 5, 5, 7, 8, 9, 7,
+ 7, 0, 0, 0, 10, 10, 10, 8,
+ 12, 13, 14, 14, 14, 14, 15, 11,
+ 11, 17, 18, 18, 18, 18, 0, 16,
+ 16, 19, 19, 19, 0, 0, 13, 20,
+ 21, 21, 20, 20, 22, 23, 22, 22,
+ 10, 24, 24, 24, 10, 25, 26, 26,
+ 25, 25, 5, 5
};
static const char _deserialize_text_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 7, 0, 0, 0, 10,
- 10, 11, 16, 19, 0, 11, 10, 22,
- 22, 10, 24, 24, 19
+ 0, 0, 0, 0, 7, 0, 0, 0,
+ 10, 10, 11, 16, 19, 0, 11, 20,
+ 22, 22, 20, 10, 25, 25, 10, 19
};
static const int deserialize_text_start = 1;
-static const int deserialize_text_first_final = 19;
+static const int deserialize_text_first_final = 20;
static const int deserialize_text_error = 0;
static const int deserialize_text_en_main = 1;
-#line 114 "hb-buffer-deserialize-text.rl"
+#line 117 "hb-buffer-deserialize-text.rl"
static hb_bool_t
@@ -424,12 +460,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 428 "hb-buffer-deserialize-text.hh"
+#line 457 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
-#line 433 "hb-buffer-deserialize-text.hh"
+#line 460 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
@@ -457,11 +493,11 @@ _resume:
case 1:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
break;
- case 3:
+ case 4:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
@@ -478,7 +514,7 @@ _resume:
case 18:
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -489,7 +525,7 @@ _resume:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
- case 21:
+ case 24:
#line 68 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
@@ -497,26 +533,30 @@ _resume:
#line 69 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
- case 23:
+ case 26:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
- case 20:
+ case 21:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
+ case 23:
+#line 72 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+ break;
case 15:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
- case 4:
+ case 3:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
@@ -535,7 +575,7 @@ _resume:
case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -574,7 +614,7 @@ _resume:
*end_ptr = p;
}
break;
- case 22:
+ case 25:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -586,7 +626,7 @@ _resume:
*end_ptr = p;
}
break;
- case 19:
+ case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -598,7 +638,7 @@ _resume:
*end_ptr = p;
}
break;
- case 24:
+ case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -610,11 +650,23 @@ _resume:
*end_ptr = p;
}
break;
+ case 19:
+#line 73 "hb-buffer-deserialize-text.rl"
+ { if (!parse_uint (tok, p, &info.mask )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (unlikely (!buffer->successful))
+ return false;
+ buffer->pos[buffer->len - 1] = pos;
+ *end_ptr = p;
+}
+ break;
case 12:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -626,8 +678,8 @@ _resume:
case 14:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -635,7 +687,7 @@ _resume:
}
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -645,7 +697,7 @@ _resume:
case 17:
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -665,8 +717,8 @@ _resume:
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -674,7 +726,7 @@ _resume:
}
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -692,8 +744,8 @@ _resume:
case 13:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -701,7 +753,7 @@ _resume:
}
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -718,7 +770,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 722 "hb-buffer-deserialize-text.hh"
+#line 715 "hb-buffer-deserialize-text.hh"
}
_again:
@@ -733,7 +785,7 @@ _again:
case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -772,7 +824,7 @@ _again:
*end_ptr = p;
}
break;
- case 22:
+ case 25:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -784,7 +836,7 @@ _again:
*end_ptr = p;
}
break;
- case 19:
+ case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -796,7 +848,7 @@ _again:
*end_ptr = p;
}
break;
- case 24:
+ case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
@@ -808,11 +860,23 @@ _again:
*end_ptr = p;
}
break;
+ case 19:
+#line 73 "hb-buffer-deserialize-text.rl"
+ { if (!parse_uint (tok, p, &info.mask )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (unlikely (!buffer->successful))
+ return false;
+ buffer->pos[buffer->len - 1] = pos;
+ *end_ptr = p;
+}
+ break;
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
@@ -820,7 +884,7 @@ _again:
}
#line 58 "hb-buffer-deserialize-text.rl"
{
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -835,14 +899,14 @@ _again:
*end_ptr = p;
}
break;
-#line 839 "hb-buffer-deserialize-text.hh"
+#line 825 "hb-buffer-deserialize-text.hh"
}
}
_out: {}
}
-#line 138 "hb-buffer-deserialize-text.rl"
+#line 141 "hb-buffer-deserialize-text.rl"
*end_ptr = p;
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
index a2170288e..f82d5ab82 100644
--- a/src/hb-buffer-deserialize-text.rl
+++ b/src/hb-buffer-deserialize-text.rl
@@ -36,8 +36,8 @@ alphtype unsigned char;
write data;
action clear_item {
- memset (&info, 0, sizeof (info));
- memset (&pos , 0, sizeof (pos ));
+ hb_memset (&info, 0, sizeof (info));
+ hb_memset (&pos , 0, sizeof (pos ));
}
action add_item {
@@ -56,7 +56,7 @@ action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; }
action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; }
action parse_glyph {
- /* TODO Unescape delimeters. */
+ /* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
@@ -65,22 +65,24 @@ action parse_glyph {
action parse_hexdigits {if (!parse_hex (tok, p, &info.codepoint )) return false; }
-action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask )) return false; }
unum = '0' | [1-9] digit*;
num = '-'? unum;
glyph_id = unum;
-glyph_name = ([^\\\]=@+,|] | '\\' [\\\]=@+,|]) *;
+glyph_name = ([^\\\]=@+,#|] | '\\' [\\\]=@+,|]) *;
glyph = (glyph_id | glyph_name) >tok %parse_glyph;
cluster = '=' (unum >tok %parse_cluster);
offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
+glyphflags= '#' (unum >tok %parse_glyph_flags);
glyph_item =
(
@@ -88,6 +90,7 @@ glyph_item =
cluster?
offsets?
advances?
+ glyphflags?
)
>clear_item
@ensure_glyphs
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 6539b8964..a458f2318 100644
--- a/src/hb-buffer-serialize.cc
+++ b/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,13 +50,13 @@ static const char *serialize_formats[] = {
const char **
hb_buffer_serialize_list_formats ()
{
- return serialize_formats;
+ return _hb_buffer_serialize_formats;
}
/**
* hb_buffer_serialize_format_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
*
* Parses a string into an #hb_buffer_serialize_format_t. Does not check if
* @str is a valid buffer serialization format, use
@@ -78,11 +78,11 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
* hb_buffer_serialize_format_to_string:
* @format: an #hb_buffer_serialize_format_t to convert.
*
- * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * Converts @format to the string corresponding it, or `NULL` if it is not a valid
* #hb_buffer_serialize_format_t.
*
* Return value: (transfer none):
- * A %NULL terminated string corresponding to @format. Should not be freed.
+ * A `NULL` terminated string corresponding to @format. Should not be freed.
*
* Since: 0.9.7
**/
@@ -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;
}
@@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
unsigned int l = p - b;
if (buf_size > l)
{
- memcpy (buf, b, l);
+ hb_memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
@@ -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.
@@ -727,7 +727,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
* hb_buffer_deserialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
* @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
* @end_ptr: (out) (optional): output pointer to the character after last
* consumed one.
* @font: (nullable): font for getting glyph IDs
@@ -736,7 +736,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
* Deserializes glyphs @buffer from textual representation in the format
* produced by hb_buffer_serialize_glyphs().
*
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
*
* Since: 0.9.7
**/
@@ -800,7 +800,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* hb_buffer_deserialize_unicode:
* @buffer: an #hb_buffer_t buffer.
* @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
* @end_ptr: (out) (optional): output pointer to the character after last
* consumed one.
* @format: the #hb_buffer_serialize_format_t of the input @buf
@@ -808,7 +808,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* Deserializes Unicode @buffer from textual representation in the format
* produced by hb_buffer_serialize_unicode().
*
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
*
* Since: 2.7.3
**/
diff --git a/src/hb-buffer-verify.cc b/src/hb-buffer-verify.cc
new file mode 100644
index 000000000..1cd52b39b
--- /dev/null
+++ b/src/hb-buffer-verify.cc
@@ -0,0 +1,439 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_BUFFER_VERIFY
+
+#include "hb-buffer.hh"
+
+
+#define BUFFER_VERIFY_ERROR "buffer verify error: "
+static inline void
+buffer_verify_error (hb_buffer_t *buffer,
+ hb_font_t *font,
+ const char *fmt,
+ ...) HB_PRINTF_FUNC(3, 4);
+
+static inline void
+buffer_verify_error (hb_buffer_t *buffer,
+ hb_font_t *font,
+ const char *fmt,
+ ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ if (buffer->messaging ())
+ {
+ buffer->message_impl (font, fmt, ap);
+ }
+ else
+ {
+ fprintf (stderr, "harfbuzz ");
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ }
+ va_end (ap);
+}
+
+static bool
+buffer_verify_monotone (hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ /* Check that clusters are monotone. */
+ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
+ buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+ {
+ bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+ unsigned int num_glyphs;
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (info[i-1].cluster != info[i].cluster &&
+ (info[i-1].cluster < info[i].cluster) != is_forward)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
+ hb_buffer_t *text_buffer,
+ hb_font_t *font,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shapers)
+{
+ if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+ buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+ {
+ /* Cannot perform this check without monotone clusters. */
+ return true;
+ }
+
+ /* Check that breaking up shaping at safe-to-break is indeed safe. */
+
+ hb_buffer_t *fragment = hb_buffer_create_similar (buffer);
+ hb_buffer_set_flags (fragment, (hb_buffer_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_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);
+
+ unsigned int num_chars;
+ hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+ /* Chop text and shape fragments. */
+ bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+ unsigned int start = 0;
+ unsigned int text_start = forward ? 0 : num_chars;
+ unsigned int text_end = text_start;
+ for (unsigned int end = 1; end < num_glyphs + 1; end++)
+ {
+ if (end < num_glyphs &&
+ (info[end].cluster == info[end-1].cluster ||
+ info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
+ continue;
+
+ /* Shape segment corresponding to glyphs start..end. */
+ if (end == num_glyphs)
+ {
+ if (forward)
+ text_end = num_chars;
+ else
+ text_start = 0;
+ }
+ else
+ {
+ if (forward)
+ {
+ unsigned int cluster = info[end].cluster;
+ while (text_end < num_chars && text[text_end].cluster < cluster)
+ text_end++;
+ }
+ else
+ {
+ unsigned int cluster = info[end - 1].cluster;
+ while (text_start && text[text_start - 1].cluster >= cluster)
+ text_start--;
+ }
+ }
+ assert (text_start < text_end);
+
+ if (0)
+ printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+ hb_buffer_clear_contents (fragment);
+
+ hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
+ if (0 < text_start)
+ flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+ if (text_end < num_chars)
+ flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+ hb_buffer_set_flags (fragment, flags);
+
+ hb_buffer_append (fragment, text_buffer, text_start, text_end);
+ if (!hb_shape_full (font, fragment, features, num_features, shapers))
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
+ hb_buffer_destroy (reconstruction);
+ hb_buffer_destroy (fragment);
+ return false;
+ }
+ 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;
+ if (forward)
+ text_start = text_end;
+ else
+ text_end = text_start;
+ }
+
+ bool ret = true;
+ hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+ ret = false;
+
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
+
+ hb_buffer_destroy (reconstruction);
+ hb_buffer_destroy (fragment);
+
+ return ret;
+}
+
+static bool
+buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
+ hb_buffer_t *text_buffer,
+ hb_font_t *font,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shapers)
+{
+ if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+ buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+ {
+ /* Cannot perform this check without monotone clusters. */
+ return true;
+ }
+
+ /* Check that shuffling up text before shaping at safe-to-concat points
+ * is indeed safe. */
+
+ /* This is what we do:
+ *
+ * 1. We shape text once. Then segment the text at all the safe-to-concat
+ * points;
+ *
+ * 2. Then we create two buffers, one containing all the even segments and
+ * one all the odd segments.
+ *
+ * 3. Because all these segments were safe-to-concat at both ends, we
+ * expect that concatenating them and shaping should NOT change the
+ * shaping results of each segment. As such, we expect that after
+ * shaping the two buffers, we still get cluster boundaries at the
+ * segment boundaries, and that those all are safe-to-concat points.
+ * Moreover, that there are NOT any safe-to-concat points within the
+ * segments.
+ *
+ * 4. Finally, we reconstruct the shaping results of the original text by
+ * simply interleaving the shaping results of the segments from the two
+ * buffers, and assert that the total shaping results is the same as
+ * the one from original buffer in step 1.
+ */
+
+ hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer),
+ hb_buffer_create_similar (buffer)};
+ hb_buffer_set_flags (fragments[0], (hb_buffer_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_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);
+ hb_buffer_set_segment_properties (fragments[1], &props);
+ hb_buffer_set_segment_properties (reconstruction, &props);
+
+ unsigned num_glyphs;
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+ unsigned num_chars;
+ hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+ bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+ if (!forward)
+ hb_buffer_reverse (buffer);
+
+ /*
+ * Split text into segments and collect into to fragment streams.
+ */
+ {
+ unsigned fragment_idx = 0;
+ unsigned start = 0;
+ unsigned text_start = 0;
+ unsigned text_end = 0;
+ for (unsigned end = 1; end < num_glyphs + 1; end++)
+ {
+ if (end < num_glyphs &&
+ (info[end].cluster == info[end-1].cluster ||
+ info[end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
+ continue;
+
+ /* Accumulate segment corresponding to glyphs start..end. */
+ if (end == num_glyphs)
+ text_end = num_chars;
+ else
+ {
+ unsigned cluster = info[end].cluster;
+ while (text_end < num_chars && text[text_end].cluster < cluster)
+ text_end++;
+ }
+ assert (text_start < text_end);
+
+ if (0)
+ printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+#if 0
+ hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
+ if (0 < text_start)
+ flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+ if (text_end < num_chars)
+ flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+ hb_buffer_set_flags (fragment, flags);
+#endif
+
+ hb_buffer_append (fragments[fragment_idx], text_buffer, text_start, text_end);
+
+ start = end;
+ text_start = text_end;
+ fragment_idx = 1 - fragment_idx;
+ }
+ }
+
+ bool ret = true;
+ hb_buffer_diff_flags_t diff;
+ /*
+ * Shape the two fragment streams.
+ */
+ if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
+ ret = false;
+ goto out;
+ }
+ 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)
+ {
+ hb_buffer_reverse (fragments[0]);
+ hb_buffer_reverse (fragments[1]);
+ }
+
+ /*
+ * Reconstruct results.
+ */
+ {
+ unsigned fragment_idx = 0;
+ unsigned fragment_start[2] {0, 0};
+ unsigned fragment_num_glyphs[2];
+ hb_glyph_info_t *fragment_info[2];
+ for (unsigned i = 0; i < 2; i++)
+ fragment_info[i] = hb_buffer_get_glyph_infos (fragments[i], &fragment_num_glyphs[i]);
+ while (fragment_start[0] < fragment_num_glyphs[0] ||
+ fragment_start[1] < fragment_num_glyphs[1])
+ {
+ unsigned fragment_end = fragment_start[fragment_idx] + 1;
+ while (fragment_end < fragment_num_glyphs[fragment_idx] &&
+ (fragment_info[fragment_idx][fragment_end].cluster == fragment_info[fragment_idx][fragment_end - 1].cluster ||
+ fragment_info[fragment_idx][fragment_end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
+ fragment_end++;
+
+ hb_buffer_append (reconstruction, fragments[fragment_idx], fragment_start[fragment_idx], fragment_end);
+
+ fragment_start[fragment_idx] = fragment_end;
+ fragment_idx = 1 - fragment_idx;
+ }
+ }
+
+ if (!forward)
+ {
+ hb_buffer_reverse (buffer);
+ hb_buffer_reverse (reconstruction);
+ }
+
+ /*
+ * Diff results.
+ */
+ diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+ ret = false;
+
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
+
+
+out:
+ hb_buffer_destroy (reconstruction);
+ hb_buffer_destroy (fragments[0]);
+ hb_buffer_destroy (fragments[1]);
+
+ return ret;
+}
+
+bool
+hb_buffer_t::verify (hb_buffer_t *text_buffer,
+ hb_font_t *font,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shapers)
+{
+ bool ret = true;
+ if (!buffer_verify_monotone (this, font))
+ ret = false;
+ if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers))
+ ret = false;
+ if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 &&
+ !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers))
+ ret = false;
+ if (!ret)
+ {
+#ifndef HB_NO_BUFFER_SERIALIZE
+ unsigned len = text_buffer->len;
+ hb_vector_t<char> bytes;
+ if (likely (bytes.resize (len * 10 + 16)))
+ {
+ hb_buffer_serialize_unicode (text_buffer,
+ 0, len,
+ bytes.arrayZ, bytes.length,
+ &len,
+ HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+ HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
+ buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
+ }
+#endif
+ }
+ return ret;
+}
+
+
+#endif
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index b4f7f7237..4b6c2d9ea 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -51,7 +51,7 @@
* Checks the equality of two #hb_segment_properties_t's.
*
* Return value:
- * %true if all properties of @a equal those of @b, %false otherwise.
+ * `true` if all properties of @a equal those of @b, `false` otherwise.
*
* Since: 0.9.7
**/
@@ -81,12 +81,51 @@ 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);
}
+/**
+ * hb_segment_properties_overlay:
+ * @p: #hb_segment_properties_t to fill in.
+ * @src: #hb_segment_properties_t to fill in from.
+ *
+ * Fills in missing fields of @p from @src in a considered manner.
+ *
+ * First, if @p does not have direction set, direction is copied from @src.
+ *
+ * Next, if @p and @src have the same direction (which can be unset), if @p
+ * does not have script set, script is copied from @src.
+ *
+ * Finally, if @p and @src have the same direction and script (which either
+ * can be unset), if @p does not have language set, language is copied from
+ * @src.
+ *
+ * Since: 3.3.0
+ **/
+void
+hb_segment_properties_overlay (hb_segment_properties_t *p,
+ const hb_segment_properties_t *src)
+{
+ if (unlikely (!p || !src))
+ return;
+ if (!p->direction)
+ p->direction = src->direction;
+
+ if (p->direction != src->direction)
+ return;
+
+ if (!p->script)
+ p->script = src->script;
+
+ if (p->script != src->script)
+ return;
+
+ if (!p->language)
+ p->language = src->language;
+}
/* Here is how the buffer works internally:
*
@@ -96,14 +135,14 @@ hb_segment_properties_hash (const hb_segment_properties_t *p)
* As an optimization, both info and out_info may point to the
* same piece of memory, which is owned by info. This remains the
* case as long as out_len doesn't exceed i at any time.
- * In that case, swap_buffers() is mostly no-op and the glyph operations
+ * In that case, sync() is mostly no-op and the glyph operations
* operate mostly in-place.
*
* As soon as out_info gets longer than info, out_info is moved over
* to an alternate buffer (which we reuse the pos buffer for), and its
* current contents (out_len entries) are copied to the new place.
*
- * This should all remain transparent to the user. swap_buffers() then
+ * This should all remain transparent to the user. sync() then
* switches info over to out_info and does housekeeping.
*/
@@ -133,12 +172,13 @@ hb_buffer_t::enlarge (unsigned int size)
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
- static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
- if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
+ unsigned new_bytes;
+ if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))
goto done;
- new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
- new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
+ static_assert (sizeof (info[0]) == sizeof (pos[0]), "");
+ new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);
+ new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);
done:
if (unlikely (!new_pos || !new_info))
@@ -169,7 +209,7 @@ hb_buffer_t::make_room_for (unsigned int num_in,
assert (have_output);
out_info = (hb_glyph_info_t *) pos;
- memcpy (out_info, info, out_len * sizeof (out_info[0]));
+ hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));
}
return true;
@@ -190,7 +230,7 @@ hb_buffer_t::shift_forward (unsigned int count)
* Ideally, we should at least set Default_Ignorable bits on
* these, as well as consistent cluster values. But the former
* is layering violation... */
- memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
+ hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
}
len += count;
idx += count;
@@ -217,11 +257,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
/* HarfBuzz-Internal API */
void
+hb_buffer_t::similar (const hb_buffer_t &src)
+{
+ hb_unicode_funcs_destroy (unicode);
+ unicode = hb_unicode_funcs_reference (src.unicode);
+ flags = src.flags;
+ cluster_level = src.cluster_level;
+ replacement = src.invisible;
+ invisible = src.invisible;
+ not_found = src.not_found;
+}
+
+void
hb_buffer_t::reset ()
{
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
+ cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
invisible = 0;
not_found = 0;
@@ -232,12 +285,12 @@ hb_buffer_t::reset ()
void
hb_buffer_t::clear ()
{
+ content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
- scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
- content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
successful = true;
+ shaping_failed = false;
have_output = false;
have_positions = false;
@@ -246,13 +299,41 @@ hb_buffer_t::clear ()
out_len = 0;
out_info = info;
- serial = 0;
+ hb_memset (context, 0, sizeof context);
+ hb_memset (context_len, 0, sizeof context_len);
- memset (context, 0, sizeof context);
- memset (context_len, 0, sizeof context_len);
+ deallocate_var_all ();
+ serial = 0;
+ scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
+}
+void
+hb_buffer_t::enter ()
+{
deallocate_var_all ();
+ serial = 0;
+ shaping_failed = false;
+ scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
+ unsigned mul;
+ if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
+ {
+ max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);
+ }
+ if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))
+ {
+ max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);
+ }
}
+void
+hb_buffer_t::leave ()
+{
+ max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+ max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
+ deallocate_var_all ();
+ serial = 0;
+ // Intentionally not reseting shaping_failed, such that it can be inspected.
+}
+
void
hb_buffer_t::add (hb_codepoint_t codepoint,
@@ -264,7 +345,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
glyph = &info[len];
- memset (glyph, 0, sizeof (*glyph));
+ hb_memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
glyph->mask = 0;
glyph->cluster = cluster;
@@ -306,9 +387,11 @@ hb_buffer_t::clear_positions ()
hb_memset (pos, 0, sizeof (pos[0]) * len);
}
-void
-hb_buffer_t::swap_buffers ()
+bool
+hb_buffer_t::sync ()
{
+ bool ret = false;
+
assert (have_output);
assert (idx <= len);
@@ -322,11 +405,39 @@ hb_buffer_t::swap_buffers ()
info = out_info;
}
len = out_len;
+ ret = true;
reset:
have_output = false;
out_len = 0;
+ out_info = info;
idx = 0;
+
+ return ret;
+}
+
+int
+hb_buffer_t::sync_so_far ()
+{
+ bool had_output = have_output;
+ unsigned out_i = out_len;
+ unsigned i = idx;
+ unsigned old_idx = idx;
+
+ if (sync ())
+ idx = out_i;
+ else
+ idx = i;
+
+ if (had_output)
+ {
+ have_output = true;
+ out_len = idx;
+ }
+
+ assert (idx <= len);
+
+ return idx - old_idx;
}
bool
@@ -396,52 +507,6 @@ hb_buffer_t::set_masks (hb_mask_t value,
}
void
-hb_buffer_t::reverse_range (unsigned int start,
- unsigned int end)
-{
- if (end - start < 2)
- return;
-
- hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
-
- if (have_positions) {
- hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
- }
-}
-
-void
-hb_buffer_t::reverse ()
-{
- if (unlikely (!len))
- return;
-
- reverse_range (0, len);
-}
-
-void
-hb_buffer_t::reverse_clusters ()
-{
- unsigned int i, start, count, last_cluster;
-
- if (unlikely (!len))
- return;
-
- reverse ();
-
- count = len;
- start = 0;
- last_cluster = info[0].cluster;
- for (i = 1; i < count; i++) {
- if (last_cluster != info[i].cluster) {
- reverse_range (start, i);
- start = i;
- last_cluster = info[i].cluster;
- }
- }
- reverse_range (start, i);
-}
-
-void
hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
@@ -509,7 +574,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;
@@ -540,29 +606,50 @@ done:
}
void
-hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
-{
- unsigned int cluster = UINT_MAX;
- cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
- _unsafe_to_break_set_mask (info, start, end, cluster);
-}
-void
-hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)
+hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info))
{
- if (!have_output)
+ /* Merge clusters and delete filtered glyphs.
+ * NOTE! We can't use out-buffer as we have positioning data. */
+ unsigned int j = 0;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
{
- unsafe_to_break_impl (start, end);
- return;
- }
+ if (filter (&info[i]))
+ {
+ /* Merge clusters.
+ * Same logic as delete_glyph(), but for in-place removal. */
- assert (start <= out_len);
- assert (idx <= end);
+ unsigned int cluster = info[i].cluster;
+ if (i + 1 < count && cluster == info[i + 1].cluster)
+ continue; /* Cluster survives; do nothing. */
- unsigned int cluster = UINT_MAX;
- cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
- cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
- _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
- _unsafe_to_break_set_mask (info, idx, end, cluster);
+ if (j)
+ {
+ /* Merge cluster backward. */
+ if (cluster < info[j - 1].cluster)
+ {
+ unsigned int mask = info[i].mask;
+ unsigned int old_cluster = info[j - 1].cluster;
+ for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
+ set_cluster (info[k - 1], cluster, mask);
+ }
+ continue;
+ }
+
+ if (i + 1 < count)
+ merge_clusters (i, i + 2); /* Merge cluster forward. */
+
+ continue;
+ }
+
+ if (j != i)
+ {
+ info[j] = info[i];
+ pos[j] = pos[i];
+ }
+ j++;
+ }
+ len = j;
}
void
@@ -610,13 +697,13 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
0, /* invisible */
0, /* not_found */
- HB_BUFFER_SCRATCH_FLAG_DEFAULT,
- HB_BUFFER_MAX_LEN_DEFAULT,
- HB_BUFFER_MAX_OPS_DEFAULT,
+
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,
+
false, /* successful */
+ true, /* shaping_failed */
false, /* have_output */
true /* have_positions */
@@ -625,16 +712,16 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
/**
- * hb_buffer_create: (Xconstructor)
+ * hb_buffer_create:
*
* Creates a new #hb_buffer_t with all properties to defaults.
*
* Return value: (transfer full):
* A newly allocated #hb_buffer_t with a reference count of 1. The initial
* reference count should be released with hb_buffer_destroy() when you are done
- * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
* be allocated, a special #hb_buffer_t object will be returned on which
- * hb_buffer_allocation_successful() returns %false.
+ * hb_buffer_allocation_successful() returns `false`.
*
* Since: 0.9.2
**/
@@ -655,6 +742,46 @@ hb_buffer_create ()
}
/**
+ * hb_buffer_create_similar:
+ * @src: An #hb_buffer_t
+ *
+ * Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only
+ * difference is that the buffer is configured similarly to @src.
+ *
+ * Return value: (transfer full):
+ * A newly allocated #hb_buffer_t, similar to hb_buffer_create().
+ *
+ * Since: 3.3.0
+ **/
+hb_buffer_t *
+hb_buffer_create_similar (const hb_buffer_t *src)
+{
+ hb_buffer_t *buffer = hb_buffer_create ();
+
+ buffer->similar (*src);
+
+ return buffer;
+}
+
+/**
+ * hb_buffer_reset:
+ * @buffer: An #hb_buffer_t
+ *
+ * Resets the buffer to its initial status, as if it was just newly created
+ * with hb_buffer_create().
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reset (hb_buffer_t *buffer)
+{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
+ buffer->reset ();
+}
+
+/**
* hb_buffer_get_empty:
*
* Fetches an empty #hb_buffer_t.
@@ -724,7 +851,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
*
* Attaches a user-data key/data pair to the specified buffer.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -751,7 +878,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
* Since: 0.9.2
**/
void *
-hb_buffer_get_user_data (hb_buffer_t *buffer,
+hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (buffer, key);
@@ -788,7 +915,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;
}
@@ -830,7 +957,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;
}
@@ -853,7 +980,6 @@ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction)
-
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
@@ -873,7 +999,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;
}
@@ -917,7 +1043,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;
}
@@ -961,7 +1087,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;
}
@@ -997,7 +1123,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;
@@ -1035,7 +1161,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;
}
@@ -1074,7 +1200,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;
}
@@ -1115,7 +1241,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;
}
@@ -1155,7 +1281,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;
}
@@ -1195,31 +1321,13 @@ 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;
}
/**
- * hb_buffer_reset:
- * @buffer: An #hb_buffer_t
- *
- * Resets the buffer to its initial status, as if it was just newly created
- * with hb_buffer_create().
- *
- * Since: 0.9.2
- **/
-void
-hb_buffer_reset (hb_buffer_t *buffer)
-{
- if (unlikely (hb_object_is_immutable (buffer)))
- return;
-
- buffer->reset ();
-}
-
-/**
* hb_buffer_clear_contents:
* @buffer: An #hb_buffer_t
*
@@ -1245,7 +1353,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer)
* Pre allocates memory for @buffer to fit at least @size number of items.
*
* Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise
+ * `true` if @buffer memory allocation succeeded, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1262,7 +1370,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
* Check if allocating memory for the buffer succeeded.
*
* Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
*
* Since: 0.9.2
**/
@@ -1307,7 +1415,7 @@ hb_buffer_add (hb_buffer_t *buffer,
* end.
*
* Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
*
* Since: 0.9.2
**/
@@ -1323,9 +1431,9 @@ hb_buffer_set_length (hb_buffer_t *buffer,
/* Wipe the new space */
if (length > buffer->len) {
- memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
+ hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
if (buffer->have_positions)
- memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
+ hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
}
buffer->len = length;
@@ -1353,7 +1461,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;
}
@@ -1393,7 +1501,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
* If buffer did not have positions before, the positions will be
* initialized to zeros, unless this function is called from
* within a buffer message callback (see hb_buffer_set_message_func()),
- * in which case %NULL is returned.
+ * in which case `NULL` is returned.
*
* Return value: (transfer none) (array length=length):
* The @buffer glyph position array.
@@ -1428,7 +1536,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
* and cleared of position data when hb_buffer_clear_contents() is called.
*
* Return value:
- * %true if the @buffer has position array, %false otherwise.
+ * `true` if the @buffer has position array, `false` otherwise.
*
* Since: 2.7.3
**/
@@ -1612,10 +1720,10 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
* @buffer: An #hb_buffer_t
* @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
* characters to append.
- * @text_length: The length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated.
* @item_offset: The offset of the first character to add to the @buffer.
* @item_length: The number of characters to add to the @buffer, or -1 for the
- * end of @text (assuming it is %NULL terminated).
+ * end of @text (assuming it is `NULL` terminated).
*
* See hb_buffer_add_codepoints().
*
@@ -1638,10 +1746,10 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
* hb_buffer_add_utf16:
* @buffer: An #hb_buffer_t
* @text: (array length=text_length): An array of UTF-16 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
* @item_offset: The offset of the first character to add to the @buffer
* @item_length: The number of characters to add to the @buffer, or -1 for the
- * end of @text (assuming it is %NULL terminated)
+ * end of @text (assuming it is `NULL` terminated)
*
* See hb_buffer_add_codepoints().
*
@@ -1664,10 +1772,10 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer,
* hb_buffer_add_utf32:
* @buffer: An #hb_buffer_t
* @text: (array length=text_length): An array of UTF-32 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
* @item_offset: The offset of the first character to add to the @buffer
* @item_length: The number of characters to add to the @buffer, or -1 for the
- * end of @text (assuming it is %NULL terminated)
+ * end of @text (assuming it is `NULL` terminated)
*
* See hb_buffer_add_codepoints().
*
@@ -1691,10 +1799,10 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
* @buffer: An #hb_buffer_t
* @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
* characters to append
- * @text_length: the length of the @text, or -1 if it is %NULL terminated
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated
* @item_offset: the offset of the first character to add to the @buffer
* @item_length: the number of characters to add to the @buffer, or -1 for the
- * end of @text (assuming it is %NULL terminated)
+ * end of @text (assuming it is `NULL` terminated)
*
* Similar to hb_buffer_add_codepoints(), but allows only access to first 256
* Unicode code points that can fit in 8-bit strings.
@@ -1717,10 +1825,10 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer,
* hb_buffer_add_codepoints:
* @buffer: a #hb_buffer_t to append characters to.
* @text: (array length=text_length): an array of Unicode code points to append.
- * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated.
* @item_offset: the offset of the first code point to add to the @buffer.
* @item_length: the number of code points to add to the @buffer, or -1 for the
- * end of @text (assuming it is %NULL terminated).
+ * end of @text (assuming it is `NULL` terminated).
*
* Appends characters from @text array to @buffer. The @item_offset is the
* position of the first character from @text that will be appended, and
@@ -1733,7 +1841,9 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer,
* marks at stat of run.
*
* This function does not check the validity of @text, it is up to the caller
- * to ensure it contains a valid Unicode code points.
+ * to ensure it contains a valid Unicode scalar values. In contrast,
+ * hb_buffer_add_utf32() can be used that takes similar input but performs
+ * sanity-check on the input.
*
* Since: 0.9.31
**/
@@ -1761,7 +1871,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
**/
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
- hb_buffer_t *source,
+ const hb_buffer_t *source,
unsigned int start,
unsigned int end)
{
@@ -1794,9 +1904,11 @@ hb_buffer_append (hb_buffer_t *buffer,
if (!buffer->have_positions && source->have_positions)
buffer->clear_positions ();
- memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
+ hb_segment_properties_overlay (&buffer->props, &source->props);
+
+ hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
- memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+ hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
{
@@ -1984,7 +2096,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
if (buf_info->cluster != ref_info->cluster)
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
- if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))
+ if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
if (contains && ref_info->codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
@@ -2039,6 +2151,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
hb_buffer_message_func_t func,
void *user_data, hb_destroy_func_t destroy)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ {
+ if (destroy)
+ destroy (user_data);
+ return;
+ }
+
if (buffer->message_destroy)
buffer->message_destroy (buffer->message_data);
@@ -2055,8 +2174,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
bool
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
{
+ assert (!have_output || (out_info == info && out_len == idx));
+
+ message_depth++;
+
char buf[100];
vsnprintf (buf, sizeof (buf), fmt, ap);
- return (bool) this->message_func (this, font, buf, this->message_data);
+ bool ret = (bool) this->message_func (this, font, buf, this->message_data);
+
+ message_depth--;
+
+ return ret;
}
#endif
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index a183cb9d4..8c1748983 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -76,18 +76,81 @@ typedef struct hb_glyph_info_t {
* @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the
* beginning of the cluster this glyph is part of,
* then both sides need to be re-shaped, as the
- * result might be different. On the flip side,
- * it means that when this flag is not present,
- * then it's safe to break the glyph-run at the
- * beginning of this cluster, and the two sides
- * represent the exact same result one would get
- * if breaking input text at the beginning of
- * this cluster and shaping the two sides
- * separately. This can be used to optimize
- * paragraph layout, by avoiding re-shaping
- * of each line after line-breaking, or limiting
- * the reshaping to a small piece around the
- * breaking point only.
+ * result might be different.
+ * On the flip side, it means that when this
+ * flag is not present, then it is safe to break
+ * the glyph-run at the beginning of this
+ * cluster, and the two sides will represent the
+ * exact same result one would get if breaking
+ * input text at the beginning of this cluster
+ * and shaping the two sides separately.
+ * This can be used to optimize paragraph
+ * layout, by avoiding re-shaping of each line
+ * after line-breaking.
+ * @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT: Indicates that if input text is changed on one
+ * side of the beginning of the cluster this glyph
+ * is part of, then the shaping results for the
+ * other side might change.
+ * Note that the absence of this flag will NOT by
+ * itself mean that it IS safe to concat text.
+ * Only two pieces of text both of which clear of
+ * this flag can be concatenated safely.
+ * This can be used to optimize paragraph
+ * layout, by avoiding re-shaping of each line
+ * after line-breaking, by limiting the
+ * reshaping to a small piece around the
+ * breaking positin only, even if the breaking
+ * position carries the
+ * #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when
+ * hyphenation or other text transformation
+ * happens at line-break position, in the following
+ * way:
+ * 1. Iterate back from the line-break position
+ * until the first cluster start position that is
+ * NOT unsafe-to-concat, 2. shape the segment from
+ * there till the end of line, 3. check whether the
+ * resulting glyph-run also is clear of the
+ * unsafe-to-concat at its start-of-text position;
+ * if it is, just splice it into place and the line
+ * is shaped; If not, move on to a position further
+ * back that is clear of unsafe-to-concat and retry
+ * from there, and repeat.
+ * At the start of next line a similar algorithm can
+ * be implemented. That is: 1. Iterate forward from
+ * the line-break position until the first cluster
+ * start position that is NOT unsafe-to-concat, 2.
+ * shape the segment from beginning of the line to
+ * that position, 3. check whether the resulting
+ * glyph-run also is clear of the unsafe-to-concat
+ * at its end-of-text position; if it is, just splice
+ * it into place and the beginning is shaped; If not,
+ * move on to a position further forward that is clear
+ * of unsafe-to-concat and retry up to there, and repeat.
+ * A slight complication will arise in the
+ * implementation of the algorithm above,
+ * because while our buffer API has a way to
+ * return flags for position corresponding to
+ * start-of-text, there is currently no position
+ * corresponding to end-of-text. This limitation
+ * can be alleviated by shaping more text than needed
+ * and looking for unsafe-to-concat flag within text
+ * clusters.
+ * The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will
+ * always imply this flag.
+ * To use this flag, you must enable the buffer flag
+ * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during
+ * shaping, otherwise the buffer flag will not be
+ * reliably produced.
+ * Since: 4.0.0
+ * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
+ Mongolian, Syriac, etc.), this flag signifies
+ that it is safe to insert a U+0640 TATWEEL
+ character before this cluster for elongation.
+ This flag does not determine the
+ script-specific elongation places, but only
+ when it is safe to do the elongation without
+ interrupting text shaping.
+ Since: 5.1.0
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Flags for #hb_glyph_info_t.
@@ -95,9 +158,11 @@ typedef struct hb_glyph_info_t {
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
- HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
+ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
+ HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002,
+ HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL = 0x00000004,
- HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
+ HB_GLYPH_FLAG_DEFINED = 0x00000007 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
@@ -170,6 +235,9 @@ hb_segment_properties_equal (const hb_segment_properties_t *a,
HB_EXTERN unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p);
+HB_EXTERN void
+hb_segment_properties_overlay (hb_segment_properties_t *p,
+ const hb_segment_properties_t *src);
/**
@@ -185,6 +253,13 @@ HB_EXTERN hb_buffer_t *
hb_buffer_create (void);
HB_EXTERN hb_buffer_t *
+hb_buffer_create_similar (const hb_buffer_t *src);
+
+HB_EXTERN void
+hb_buffer_reset (hb_buffer_t *buffer);
+
+
+HB_EXTERN hb_buffer_t *
hb_buffer_get_empty (void);
HB_EXTERN hb_buffer_t *
@@ -201,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_bool_t replace);
HB_EXTERN void *
-hb_buffer_get_user_data (hb_buffer_t *buffer,
+hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key);
@@ -224,7 +299,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
@@ -232,21 +307,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,
@@ -254,14 +329,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
@@ -295,7 +370,24 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
* flag indicating that a dotted circle should
* not be inserted in the rendering of incorrect
- * character sequences (such at <0905 093E>). Since: 2.4
+ * character sequences (such at <0905 093E>). Since: 2.4.0
+ * @HB_BUFFER_FLAG_VERIFY:
+ * flag indicating that the hb_shape() call and its variants
+ * should perform various verification processes on the results
+ * of the shaping operation on the buffer. If the verification
+ * fails, then either a buffer message is sent, if a message
+ * handler is installed on the buffer, or a message is written
+ * to standard error. In either case, the shaping result might
+ * be modified to show the failed output. Since: 3.4.0
+ * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT:
+ * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
+ * glyph-flag should be produced by the shaper. By default
+ * it will not be produced since it incurs a cost. Since: 4.0.0
+ * @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL:
+ * flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+ * glyph-flag should be produced by the shaper. By default
+ * it will not be produced. Since: 5.1.0
+ * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
*
* Flags for #hb_buffer_t.
*
@@ -307,7 +399,12 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
- HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
+ HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
+ HB_BUFFER_FLAG_VERIFY = 0x00000020u,
+ HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u,
+ HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL = 0x00000080u,
+
+ HB_BUFFER_FLAG_DEFINED = 0x000000FFu
} hb_buffer_flags_t;
HB_EXTERN void
@@ -315,7 +412,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:
@@ -357,7 +454,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:
@@ -374,25 +471,26 @@ 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);
-HB_EXTERN void
-hb_buffer_reset (hb_buffer_t *buffer);
+/*
+ * Content API.
+ */
HB_EXTERN void
hb_buffer_clear_contents (hb_buffer_t *buffer);
@@ -460,7 +558,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
- hb_buffer_t *source,
+ const hb_buffer_t *source,
unsigned int start,
unsigned int end);
@@ -469,7 +567,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 */
@@ -503,6 +601,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().
*
@@ -515,7 +614,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;
/**
@@ -557,24 +658,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
HB_EXTERN unsigned int
hb_buffer_serialize_unicode (hb_buffer_t *buffer,
- unsigned int start,
- unsigned int end,
- char *buf,
- unsigned int buf_size,
- unsigned int *buf_consumed,
- hb_buffer_serialize_format_t format,
- hb_buffer_serialize_flags_t flags);
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed,
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags);
HB_EXTERN unsigned int
hb_buffer_serialize (hb_buffer_t *buffer,
- unsigned int start,
- unsigned int end,
- char *buf,
- unsigned int buf_size,
- unsigned int *buf_consumed,
- hb_font_t *font,
- hb_buffer_serialize_format_t format,
- hb_buffer_serialize_flags_t flags);
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed,
+ hb_font_t *font,
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags);
HB_EXTERN hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
@@ -586,10 +687,10 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
HB_EXTERN hb_bool_t
hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
- const char *buf,
- int buf_len,
- const char **end_ptr,
- hb_buffer_serialize_format_t format);
+ const char *buf,
+ int buf_len,
+ const char **end_ptr,
+ hb_buffer_serialize_format_t format);
@@ -669,16 +770,16 @@ hb_buffer_diff (hb_buffer_t *buffer,
* hb_buffer_message_func_t:
* @buffer: An #hb_buffer_t to work upon
* @font: The #hb_font_t the @buffer is shaped with
- * @message: %NULL-terminated message passed to the function
+ * @message: `NULL`-terminated message passed to the function
* @user_data: User data pointer passed by the caller
*
* A callback method for #hb_buffer_t. The method gets called with the
* #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
* message describing what step of the shaping process will be performed.
- * Returning %false from this method will skip this shaping step and move to
+ * Returning `false` from this method will skip this shaping step and move to
* the next one.
*
- * Return value: %true to perform the shaping step, %false to skip it.
+ * Return value: `true` to perform the shaping step, `false` to skip it.
*
* Since: 1.1.3
*/
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index bde28933e..bb1efe9dd 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -32,6 +32,7 @@
#include "hb.hh"
#include "hb-unicode.hh"
+#include "hb-set-digest.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
@@ -57,6 +58,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);
@@ -67,14 +69,15 @@ enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
- HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
- HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u,
-
- /* 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,
+ 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 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);
@@ -87,22 +90,26 @@ struct hb_buffer_t
{
hb_object_header_t header;
- /* Information about how the text in the buffer should be treated */
+ /*
+ * Information about how the text in the buffer should be treated.
+ */
+
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
hb_codepoint_t not_found; /* 0 or something else. */
- hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
- unsigned int max_len; /* Maximum allowed len. */
- int max_ops; /* Maximum allowed operations. */
- /* Buffer contents */
+ /*
+ * Buffer contents
+ */
+
hb_buffer_content_type_t content_type;
hb_segment_properties_t props; /* Script, language, direction */
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 */
@@ -115,8 +122,6 @@ struct hb_buffer_t
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
- unsigned int serial;
-
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
@@ -124,7 +129,23 @@ struct hb_buffer_t
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
- /* Debugging API */
+
+ /*
+ * Managed by enter / leave
+ */
+
+ uint8_t allocated_var_bits;
+ uint8_t serial;
+ hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
+ unsigned int max_len; /* Maximum allowed len. */
+ int max_ops; /* Maximum allowed operations. */
+ /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
+
+
+ /*
+ * Messaging callback
+ */
+
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
void *message_data;
@@ -134,11 +155,6 @@ struct hb_buffer_t
static constexpr unsigned message_depth = 0u;
#endif
- /* Internal debugging. */
- /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
-#ifndef HB_NDEBUG
- uint8_t allocated_var_bits;
-#endif
/* Methods */
@@ -147,38 +163,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]; }
@@ -190,23 +208,97 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
+ hb_set_digest_t digest () const
+ {
+ hb_set_digest_t d;
+ d.init ();
+ d.add_array (&info[0].codepoint, len, sizeof (info[0]));
+ return d;
+ }
+
+ HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
+ /* Called around shape() */
+ HB_INTERNAL void enter ();
+ HB_INTERNAL void leave ();
+
+#ifndef HB_NO_BUFFER_VERIFY
+ HB_INTERNAL
+#endif
+ bool verify (hb_buffer_t *text_buffer,
+ hb_font_t *font,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shapers)
+#ifndef HB_NO_BUFFER_VERIFY
+ ;
+#else
+ { return true; }
+#endif
+
unsigned int backtrack_len () const { return have_output ? out_len : idx; }
unsigned int lookahead_len () const { return len - idx; }
- unsigned int next_serial () { return serial++; }
+ uint8_t next_serial () { return ++serial ? serial : ++serial; }
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
- HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
- HB_INTERNAL void reverse ();
- HB_INTERNAL void reverse_clusters ();
+ void reverse_range (unsigned start, unsigned end)
+ {
+ hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
+ if (have_positions)
+ hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
+ }
+ void reverse () { reverse_range (0, len); }
+
+ template <typename FuncType>
+ void reverse_groups (const FuncType& group,
+ bool merge_clusters = false)
+ {
+ if (unlikely (!len))
+ return;
+
+ unsigned start = 0;
+ unsigned i;
+ for (i = 1; i < len; i++)
+ {
+ if (!group (info[i - 1], info[i]))
+ {
+ if (merge_clusters)
+ this->merge_clusters (start, i);
+ reverse_range (start, i);
+ start = i;
+ }
+ }
+ if (merge_clusters)
+ this->merge_clusters (start, i);
+ reverse_range (start, i);
+
+ reverse ();
+ }
+
+ template <typename FuncType>
+ unsigned group_end (unsigned start, const FuncType& group) const
+ {
+ while (++start < len && group (info[start - 1], info[start]))
+ ;
+
+ return start;
+ }
+
+ static bool _cluster_group_func (const hb_glyph_info_t& a,
+ const hb_glyph_info_t& b)
+ { return a.cluster == b.cluster; }
+
+ void reverse_clusters () { reverse_groups (_cluster_group_func); }
+
HB_INTERNAL void guess_segment_properties ();
- HB_INTERNAL void swap_buffers ();
+ HB_INTERNAL bool sync ();
+ HB_INTERNAL int sync_so_far ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
@@ -319,16 +411,101 @@ struct hb_buffer_t
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph ();
+ HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info));
+
- void unsafe_to_break (unsigned int start,
- unsigned int end)
+
+ /* Adds glyph flags in mask to infos with clusters between start and end.
+ * The start index will be from out-buffer if from_out_buffer is true.
+ * If interior is true, then the cluster having the minimum value is skipped. */
+ void _set_glyph_flags (hb_mask_t mask,
+ unsigned start = 0,
+ unsigned end = (unsigned) -1,
+ bool interior = false,
+ bool from_out_buffer = false)
{
- if (end - start < 2)
+ end = hb_min (end, len);
+
+ if (interior && !from_out_buffer && end - start < 2)
+ return;
+
+ scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+
+ if (!from_out_buffer || !have_output)
+ {
+ if (!interior)
+ {
+ for (unsigned i = start; i < end; i++)
+ info[i].mask |= mask;
+ }
+ else
+ {
+ unsigned cluster = _infos_find_min_cluster (info, start, end);
+ _infos_set_glyph_flags (info, start, end, cluster, mask);
+ }
+ }
+ else
+ {
+ assert (start <= out_len);
+ assert (idx <= end);
+
+ if (!interior)
+ {
+ for (unsigned i = start; i < out_len; i++)
+ out_info[i].mask |= mask;
+ for (unsigned i = idx; i < end; i++)
+ info[i].mask |= mask;
+ }
+ else
+ {
+ unsigned cluster = _infos_find_min_cluster (info, idx, end);
+ cluster = _infos_find_min_cluster (out_info, start, out_len, cluster);
+
+ _infos_set_glyph_flags (out_info, start, out_len, cluster, mask);
+ _infos_set_glyph_flags (info, idx, end, cluster, mask);
+ }
+ }
+ }
+
+ void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
+ {
+ _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
+ start, end,
+ true);
+ }
+ void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
+ {
+ if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
+ {
+ unsafe_to_break (start, end);
+ return;
+ }
+ _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
+ start, end,
+ true);
+ }
+ void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
+ {
+ if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
+ return;
+ _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
+ start, end,
+ true);
+ }
+ void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
+ {
+ _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
+ start, end,
+ true, true);
+ }
+ void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
+ {
+ if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
return;
- unsafe_to_break_impl (start, end);
+ _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
+ start, end,
+ false, true);
}
- HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end);
- HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end);
/* Internal methods */
@@ -398,18 +575,14 @@ struct hb_buffer_t
#ifdef HB_NO_BUFFER_MESSAGE
return true;
#else
- if (!messaging ())
+ if (likely (!messaging ()))
return true;
- message_depth++;
-
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
- message_depth--;
-
return ret;
#endif
}
@@ -419,75 +592,59 @@ struct hb_buffer_t
set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
{
if (inf.cluster != cluster)
- {
- if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
- inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
- else
- inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
- }
+ inf.mask = (inf.mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
inf.cluster = cluster;
}
-
- unsigned int
- _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
- unsigned int start, unsigned int end,
- unsigned int cluster) const
- {
- for (unsigned int i = start; i < end; i++)
- cluster = hb_min (cluster, infos[i].cluster);
- return cluster;
- }
void
- _unsafe_to_break_set_mask (hb_glyph_info_t *infos,
- unsigned int start, unsigned int end,
- unsigned int cluster)
+ _infos_set_glyph_flags (hb_glyph_info_t *infos,
+ unsigned int start, unsigned int end,
+ unsigned int cluster,
+ hb_mask_t mask)
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
{
- scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
- infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+ scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+ infos[i].mask |= mask;
}
}
+ static unsigned
+ _infos_find_min_cluster (const hb_glyph_info_t *infos,
+ unsigned start, unsigned end,
+ unsigned cluster = UINT_MAX)
+ {
+ for (unsigned int i = start; i < end; i++)
+ cluster = hb_min (cluster, infos[i].cluster);
+ return cluster;
+ }
- void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
- void safe_to_break_all ()
+ void clear_glyph_flags (hb_mask_t mask = 0)
{
for (unsigned int i = 0; i < len; i++)
- info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+ info[i].mask = (info[i].mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
}
};
DECLARE_NULL_INSTANCE (hb_buffer_t);
-/* Loop over clusters. Duplicated in foreach_syllable(). */
-#define foreach_cluster(buffer, start, end) \
+#define foreach_group(buffer, start, end, group_func) \
for (unsigned int \
_count = buffer->len, \
- start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
+ start = 0, end = _count ? buffer->group_end (0, group_func) : 0; \
start < _count; \
- start = end, end = _next_cluster (buffer, start))
+ start = end, end = buffer->group_end (start, group_func))
-static inline unsigned int
-_next_cluster (hb_buffer_t *buffer, unsigned int start)
-{
- hb_glyph_info_t *info = buffer->info;
- unsigned int count = buffer->len;
-
- unsigned int cluster = info[start].cluster;
- while (++start < count && cluster == info[start].cluster)
- ;
-
- return start;
-}
+#define foreach_cluster(buffer, start, end) \
+ foreach_group (buffer, start, end, hb_buffer_t::_cluster_group_func)
#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/src/hb-cache.hh b/src/hb-cache.hh
index e617b75de..f8c8108f1 100644
--- a/src/hb-cache.hh
+++ b/src/hb-cache.hh
@@ -32,12 +32,21 @@
/* 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,
+ bool thread_safe=true>
struct hb_cache_t
{
+ using item_t = typename std::conditional<thread_safe,
+ hb_atomic_int_t,
+ typename std::conditional<key_bits + value_bits - cache_bits <= 16,
+ short,
+ int>::type
+ >::type;
+
static_assert ((key_bits >= cache_bits), "");
- static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), "");
- static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), "");
+ static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
void init () { clear (); }
void fini () {}
@@ -45,14 +54,14 @@ struct hb_cache_t
void clear ()
{
for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
- values[i].set_relaxed (-1);
+ values[i] = -1;
}
bool get (unsigned int key, unsigned int *value) const
{
unsigned int k = key & ((1u<<cache_bits)-1);
- unsigned int v = values[k].get_relaxed ();
- if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) ||
+ unsigned int v = values[k];
+ if ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t) && v == (unsigned int) -1) ||
(v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1u<<value_bits)-1);
@@ -65,16 +74,13 @@ struct hb_cache_t
return false; /* Overflows */
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
- values[k].set_relaxed (v);
+ values[k] = v;
return true;
}
private:
- hb_atomic_int_t values[1u<<cache_bits];
+ item_t values[1u<<cache_bits];
};
-typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
-typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
-
#endif /* HB_CACHE_HH */
diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh
index c251e2d0e..49805a89c 100644
--- a/src/hb-cff-interp-common.hh
+++ b/src/hb-cff-interp-common.hh
@@ -217,9 +217,6 @@ inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2:
struct number_t
{
- void init () { set_real (0.0); }
- void fini () {}
-
void set_int (int v) { value = v; }
int to_int () const { return value; }
@@ -245,12 +242,15 @@ struct number_t
}
protected:
- double value;
+ double value = 0.;
};
/* byte string */
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
{
+ hb_ubytes_t as_ubytes (unsigned l) const
+ { return hb_ubytes_t ((const unsigned char *) this, l); }
+
// encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
template <typename T, typename V>
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
@@ -277,130 +277,91 @@ 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
{
- byte_str_ref_t () { init (); }
+ byte_str_ref_t ()
+ : str () {}
- void init ()
- {
- str = byte_str_t ();
- offset = 0;
- error = false;
- }
-
- void fini () {}
+ byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0)
+ : str (str_) { set_offset (offset_); }
- byte_str_ref_t (const byte_str_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_;
- error = false;
+ set_offset (offset_);
}
const unsigned char& operator [] (int i) {
- if (unlikely ((unsigned int) (offset + i) >= str.length))
+ if (unlikely ((unsigned int) (get_offset () + i) >= str.length))
{
set_error ();
return Null (unsigned char);
}
- return str[offset + i];
+ return str.arrayZ[get_offset () + i];
}
- /* Conversion to byte_str_t */
- operator byte_str_t () const { return str.sub_str (offset, str.length - offset); }
+ unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; }
+
+ /* Conversion to hb_ubytes_t */
+ operator hb_ubytes_t () const { return str.sub_array (get_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 get_offset () + count <= str.length; }
void inc (unsigned int count=1)
{
- if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
- {
- offset += count;
- }
- else
- {
- offset = str.length;
- set_error ();
- }
+ /* Automatically puts us in error if count is out-of-range. */
+ set_offset (get_offset () + count);
}
- void set_error () { error = true; }
- bool in_error () const { return error; }
+ /* We (ab)use ubytes backwards_length as a cursor (called offset),
+ * as well as to store error condition. */
+
+ unsigned get_offset () const { return str.backwards_length; }
+ void set_offset (unsigned offset) { str.backwards_length = offset; }
- byte_str_t str;
- unsigned int offset; /* beginning of the sub-string within str */
+ void set_error () { str.backwards_length = str.length + 1; }
+ bool in_error () const { return str.backwards_length > str.length; }
+
+ unsigned total_size () const { return str.length; }
protected:
- bool error;
+ hb_ubytes_t str;
};
-typedef hb_vector_t<byte_str_t> byte_str_array_t;
+using byte_str_array_t = hb_vector_t<hb_ubytes_t>;
/* stack */
template <typename ELEM, int LIMIT>
struct cff_stack_t
{
- void init ()
- {
- error = false;
- count = 0;
- elements.init ();
- elements.resize (kSizeLimit);
- for (unsigned int i = 0; i < elements.length; i++)
- elements[i].init ();
- }
- void fini () { elements.fini_deep (); }
-
ELEM& operator [] (unsigned int i)
{
- if (unlikely (i >= count)) set_error ();
+ if (unlikely (i >= count))
+ {
+ set_error ();
+ return Crap (ELEM);
+ }
return elements[i];
}
void push (const ELEM &v)
{
- if (likely (count < elements.length))
+ if (likely (count < LIMIT))
elements[count++] = v;
else
set_error ();
}
ELEM &push ()
{
- if (likely (count < elements.length))
+ if (likely (count < LIMIT))
return elements[count++];
else
{
@@ -429,7 +390,7 @@ struct cff_stack_t
const ELEM& peek ()
{
- if (unlikely (count < 0))
+ if (unlikely (count == 0))
{
set_error ();
return Null (ELEM);
@@ -439,7 +400,7 @@ struct cff_stack_t
void unpop ()
{
- if (likely (count < elements.length))
+ if (likely (count < LIMIT))
count++;
else
set_error ();
@@ -447,18 +408,19 @@ struct cff_stack_t
void clear () { count = 0; }
- bool in_error () const { return (error || elements.in_error ()); }
+ bool in_error () const { return (error); }
void set_error () { error = true; }
unsigned int get_count () const { return count; }
bool is_empty () const { return !count; }
- static constexpr unsigned kSizeLimit = LIMIT;
+ hb_array_t<const ELEM> sub_array (unsigned start, unsigned length) const
+ { return hb_array_t<const ELEM> (elements).sub_array (start, length); }
- protected:
- bool error;
- unsigned int count;
- hb_vector_t<ELEM> elements;
+ private:
+ bool error = false;
+ unsigned int count = 0;
+ ELEM elements[LIMIT];
};
/* argument stack */
@@ -513,9 +475,6 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
return true;
}
- hb_array_t<const ARG> get_subarray (unsigned int start) const
- { return S::elements.sub_array (start); }
-
private:
typedef cff_stack_t<ARG, 513> S;
};
@@ -523,11 +482,15 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
/* an operator prefixed by its operands in a byte string */
struct op_str_t
{
- void init () {}
- void fini () {}
+ /* This used to have a hb_ubytes_t. Using a pointer and length
+ * in a particular order, saves 8 bytes in this struct and more
+ * in our parsed_cs_op_t subclass. */
+
+ const unsigned char *ptr = nullptr;
op_code_t op;
- byte_str_t str;
+
+ uint8_t length = 0;
};
/* base of OP_SERIALIZER */
@@ -538,9 +501,11 @@ struct op_serializer_t
{
TRACE_SERIALIZE (this);
- HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+ unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
if (unlikely (!d)) return_trace (false);
- memcpy (d, &opstr.str[0], opstr.str.length);
+ /* Faster than hb_memcpy for small strings. */
+ for (unsigned i = 0; i < opstr.length; i++)
+ d[i] = opstr.ptr[i];
return_trace (true);
}
};
@@ -553,34 +518,42 @@ struct parsed_values_t
opStart = 0;
values.init ();
}
- void fini () { values.fini_deep (); }
+ void fini () { values.fini (); }
+
+ void alloc (unsigned n)
+ {
+ values.alloc (n);
+ }
void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
{
VAL *val = values.push ();
val->op = op;
- val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart);
- opStart = str_ref.offset;
+ auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
+ val->ptr = arr.arrayZ;
+ val->length = arr.length;
+ opStart = str_ref.get_offset ();
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
{
VAL *val = values.push (v);
val->op = op;
- val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart);
- opStart = str_ref.offset;
+ auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
+ val->ptr = arr.arrayZ;
+ val->length = arr.length;
+ opStart = str_ref.get_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;
}
unsigned get_count () const { return values.length; }
- const VAL &get_value (unsigned int i) const { return values[i]; }
- const VAL &operator [] (unsigned int i) const { return get_value (i); }
+ const VAL &operator [] (unsigned int i) const { return values[i]; }
unsigned int opStart;
hb_vector_t<VAL> values;
@@ -589,32 +562,29 @@ 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 (); }
+ { return str_ref.in_error () || argStack.in_error (); }
- void set_error () { error = true; }
+ void set_error () { str_ref.set_error (); }
op_code_t fetch_op ()
{
op_code_t op = OpCode_Invalid;
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
- op = (op_code_t)(unsigned char)str_ref[0];
+ op = (op_code_t) str_ref.head_unchecked ();
+ str_ref.inc ();
if (op == OpCode_escape) {
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
- op = Make_OpCode_ESC(str_ref[1]);
+ op = Make_OpCode_ESC (str_ref.head_unchecked ());
str_ref.inc ();
}
- str_ref.inc ();
return op;
}
@@ -629,11 +599,9 @@ struct interp_env_t
str_ref;
arg_stack_t<ARG>
argStack;
- protected:
- bool error;
};
-typedef interp_env_t<> num_interp_env_t;
+using num_interp_env_t = interp_env_t<>;
template <typename ARG=number_t>
struct opset_t
@@ -676,11 +644,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/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh
index 52d778ffe..f93c83ab4 100644
--- a/src/hb-cff-interp-cs-common.hh
+++ b/src/hb-cff-interp-cs-common.hh
@@ -57,6 +57,7 @@ struct call_context_t
/* call stack */
const unsigned int kMaxCallLimit = 10;
+const unsigned int kMaxOps = 10000;
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
template <typename SUBRS>
@@ -79,10 +80,10 @@ struct biased_subrs_t
unsigned int get_count () const { return subrs ? subrs->count : 0; }
unsigned int get_bias () const { return bias; }
- byte_str_t operator [] (unsigned int index) const
+ hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (!subrs || index >= subrs->count))
- return Null (byte_str_t);
+ return hb_ubytes_t ();
else
return (*subrs)[index];
}
@@ -94,12 +95,6 @@ struct biased_subrs_t
struct point_t
{
- void init ()
- {
- x.init ();
- y.init ();
- }
-
void set_int (int _x, int _y)
{
x.set_int (_x);
@@ -118,26 +113,21 @@ struct point_t
template <typename ARG, typename SUBRS>
struct cs_interp_env_t : interp_env_t<ARG>
{
- void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
+ cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) :
+ interp_env_t<ARG> (str)
{
- interp_env_t<ARG>::init (str);
-
context.init (str, CSType_CharString);
seen_moveto = true;
seen_hintmask = false;
hstem_count = 0;
vstem_count = 0;
hintmask_size = 0;
- pt.init ();
- callStack.init ();
+ pt.set_int (0, 0);
globalSubrs.init (globalSubrs_);
localSubrs.init (localSubrs_);
}
- void fini ()
+ ~cs_interp_env_t ()
{
- interp_env_t<ARG>::fini ();
-
- callStack.fini ();
globalSubrs.fini ();
localSubrs.fini ();
}
@@ -841,7 +831,6 @@ struct path_procs_t
if (likely (env.argStack.get_count () == 11))
{
point_t d;
- d.init ();
for (unsigned int i = 0; i < 10; i += 2)
d.move (env.eval_arg (i), env.eval_arg (i+1));
@@ -887,11 +876,19 @@ 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);
+ unsigned max_ops = kMaxOps;
for (;;) {
+ if (unlikely (!--max_ops))
+ {
+ SUPER::env.set_error ();
+ break;
+ }
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (SUPER::env.in_error ()))
return false;
diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh
index a520ca3bc..79fe9b42c 100644
--- a/src/hb-cff-interp-dict-common.hh
+++ b/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/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh
index 1c8762c17..b306c2ecc 100644
--- a/src/hb-cff1-interp-cs.hh
+++ b/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/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh
index d96156644..00c25800e 100644
--- a/src/hb-cff2-interp-cs.hh
+++ b/src/hb-cff2-interp-cs.hh
@@ -35,30 +35,20 @@ using namespace OT;
struct blend_arg_t : number_t
{
- void init ()
- {
- number_t::init ();
- deltas.init ();
- }
-
- void fini ()
- {
- number_t::fini ();
- deltas.fini_deep ();
- }
-
void set_int (int v) { reset_blends (); number_t::set_int (v); }
void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
void set_real (double v) { reset_blends (); number_t::set_real (v); }
void set_blends (unsigned int numValues_, unsigned int valueIndex_,
- unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
+ hb_array_t<const blend_arg_t> blends_)
{
numValues = numValues_;
valueIndex = valueIndex_;
- deltas.resize (numBlends);
+ unsigned numBlends = blends_.length;
+ if (unlikely (!deltas.resize (numBlends)))
+ return;
for (unsigned int i = 0; i < numBlends; i++)
- deltas[i] = blends_[i];
+ deltas.arrayZ[i] = blends_.arrayZ[i];
}
bool blending () const { return deltas.length > 0; }
@@ -73,17 +63,16 @@ struct blend_arg_t : number_t
hb_vector_t<number_t> deltas;
};
-typedef interp_env_t<blend_arg_t> BlendInterpEnv;
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
-struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
+template <typename ELEM>
+struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
{
template <typename ACC>
- void init (const byte_str_t &str, ACC &acc, unsigned int fd,
- const int *coords_=nullptr, unsigned int num_coords_=0)
+ cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
+ const int *coords_=nullptr, unsigned int num_coords_=0)
+ : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
{
- SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
-
coords = coords_;
num_coords = num_coords_;
varStore = acc.varStore;
@@ -112,18 +101,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
return OpCode_return;
}
- const blend_arg_t& eval_arg (unsigned int i)
+ const ELEM& eval_arg (unsigned int i)
{
- blend_arg_t &arg = argStack[i];
- blend_arg (arg);
- return arg;
+ return SUPER::argStack[i];
}
- const blend_arg_t& pop_arg ()
+ const ELEM& pop_arg ()
{
- blend_arg_t &arg = argStack.pop ();
- blend_arg (arg);
- return arg;
+ return SUPER::argStack.pop ();
}
void process_blend ()
@@ -134,7 +119,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
if (do_blend)
{
if (unlikely (!scalars.resize (region_count)))
- set_error ();
+ SUPER::set_error ();
else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&scalars[0], region_count);
@@ -145,10 +130,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
void process_vsindex ()
{
- unsigned int index = argStack.pop_uint ();
+ unsigned int index = SUPER::argStack.pop_uint ();
if (unlikely (seen_vsindex () || seen_blend))
{
- set_error ();
+ SUPER::set_error ();
}
else
{
@@ -163,22 +148,19 @@ 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);
+ unsigned count = scalars.length;
+ for (unsigned i = 0; i < count; i++)
+ v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
}
}
+ return v;
}
protected:
@@ -192,22 +174,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
bool seen_vsindex_;
bool seen_blend;
- typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
+ typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
};
-template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
-struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
+template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
+struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
{
- static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
+ static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
{
switch (op) {
case OpCode_callsubr:
case OpCode_callgsubr:
- /* a subroutine number shoudln't be a blended value */
+ /* a subroutine number shouldn't be a blended value */
+#if 0
if (unlikely (env.argStack.peek ().blending ()))
{
env.set_error ();
break;
}
+#endif
SUPER::process_op (op, env, param);
break;
@@ -216,11 +200,13 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
break;
case OpCode_vsindexcs:
+#if 0
if (unlikely (env.argStack.peek ().blending ()))
{
env.set_error ();
break;
}
+#endif
OPSET::process_vsindex (env, param);
break;
@@ -229,7 +215,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);
+ }
+ template <typename T = ELEM,
+ hb_enable_if (!hb_is_same (T, blend_arg_t))>
+ static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
+ ELEM &arg,
+ const hb_array_t<const ELEM> blends,
+ unsigned n, unsigned i)
+ {
+ arg.set_real (arg.to_real () + env.blend_deltas (blends));
+ }
+
+ static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
{
unsigned int n, k;
@@ -246,26 +251,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/src/hb-common.cc b/src/hb-common.cc
index 26c8ad0f4..e9f9cfeb5 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -29,10 +29,31 @@
#include "hb.hh"
#include "hb-machinery.hh"
+#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
+#define HB_NO_SETLOCALE 1
+#endif
+
+#ifndef HB_NO_SETLOCALE
+
#include <locale.h>
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h> // Needed on BSD/OS X for uselocale
+#endif
+
+#ifdef WIN32
+#define hb_locale_t _locale_t
+#else
+#define hb_locale_t locale_t
+#endif
+#define hb_setlocale setlocale
+#define hb_uselocale uselocale
+
+#else
+
+#define hb_locale_t void *
+#define hb_setlocale(Category, Locale) "C"
+#define hb_uselocale(Locale) ((hb_locale_t) 0)
-#ifdef HB_NO_SETLOCALE
-#define setlocale(Category, Locale) "C"
#endif
/**
@@ -78,7 +99,7 @@ _hb_options_init ()
}
/* This is idempotent and threadsafe. */
- _hb_options.set_relaxed (u.i);
+ _hb_options = u.i;
}
@@ -87,7 +108,7 @@ _hb_options_init ()
/**
* hb_tag_from_string:
* @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
*
* Converts a string into an #hb_tag_t. Valid tags
* are four characters. Shorter input strings will be
@@ -122,7 +143,7 @@ hb_tag_from_string (const char *str, int len)
* @tag: #hb_tag_t to convert
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
*
- * Converts an #hb_tag_t to a string and returns it in @buf.
+ * Converts an #hb_tag_t to a string and returns it in @buf.
* Strings will be four characters long.
*
* Since: 0.9.5
@@ -139,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",
@@ -149,15 +170,15 @@ const char direction_strings[][4] = {
/**
* hb_direction_from_string:
* @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
*
- * Converts a string to an #hb_direction_t.
+ * Converts a string to an #hb_direction_t.
*
* Matching is loose and applies only to the first letter. For
* examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
*
* Unmatched strings will return #HB_DIRECTION_INVALID.
- *
+ *
* Return value: The #hb_direction_t matching @str
*
* Since: 0.9.2
@@ -264,7 +285,7 @@ struct hb_language_item_t {
lang = (hb_language_t) hb_malloc(len);
if (likely (lang))
{
- memcpy((unsigned char *) lang, s, len);
+ hb_memcpy((unsigned char *) lang, s, len);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
}
@@ -336,7 +357,7 @@ retry:
* hb_language_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing
* a BCP 47 language tag
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
*
* Converts @str representing a BCP 47 language tag to the corresponding
* #hb_language_t.
@@ -358,7 +379,7 @@ hb_language_from_string (const char *str, int len)
/* NUL-terminate it. */
char strbuf[64];
len = hb_min (len, (int) sizeof (strbuf) - 1);
- memcpy (strbuf, str, len);
+ hb_memcpy (strbuf, str, len);
strbuf[len] = '\0';
item = lang_find_or_insert (strbuf);
}
@@ -375,7 +396,7 @@ hb_language_from_string (const char *str, int len)
* Converts an #hb_language_t to a string.
*
* Return value: (transfer none):
- * A %NULL-terminated string representing the @language. Must not be freed by
+ * A `NULL`-terminated string representing the @language. Must not be freed by
* the caller.
*
* Since: 0.9.2
@@ -413,13 +434,45 @@ hb_language_get_default ()
hb_language_t language = default_language;
if (unlikely (language == HB_LANGUAGE_INVALID))
{
- language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
+ language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
(void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
}
return language;
}
+/**
+ * hb_language_matches:
+ * @language: The #hb_language_t to work on
+ * @specific: Another #hb_language_t
+ *
+ * Check whether a second language tag is the same or a more
+ * specific version of the provided language tag. For example,
+ * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".
+ *
+ * Return value: `true` if languages match, `false` otherwise.
+ *
+ * Since: 5.0.0
+ **/
+hb_bool_t
+hb_language_matches (hb_language_t language,
+ hb_language_t specific)
+{
+ if (language == specific) return true;
+ if (!language || !specific) return false;
+
+ const char *l = language->s;
+ const char *s = specific->s;
+ unsigned ll = strlen (l);
+ unsigned sl = strlen (s);
+
+ if (ll > sl)
+ return false;
+
+ return strncmp (l, s, ll) == 0 &&
+ (s[ll] == '\0' || s[ll] == '-');
+}
+
/* hb_script_t */
@@ -477,7 +530,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
* hb_script_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing an
* ISO 15924 tag.
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
*
* Converts a string @str representing an ISO 15924 script tag to a
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
@@ -672,8 +725,8 @@ hb_version_string ()
* Tests the library version against a minimum value,
* as three integer components.
*
- * Return value: %true if the library is equal to or greater than
- * the test value, %false otherwise
+ * Return value: `true` if the library is equal to or greater than
+ * the test value, `false` otherwise
*
* Since: 0.9.30
**/
@@ -860,7 +913,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
* Parses a string into a #hb_feature_t.
@@ -902,7 +955,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
* </informaltable>
*
* Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
*
* Since: 0.9.5
**/
@@ -923,7 +976,7 @@ hb_feature_from_string (const char *str, int len,
}
if (feature)
- memset (feature, 0, sizeof (*feature));
+ hb_memset (feature, 0, sizeof (*feature));
return false;
}
@@ -933,7 +986,7 @@ hb_feature_from_string (const char *str, int len,
* @buf: (array length=size) (out): output string
* @size: the allocated size of @buf
*
- * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * Converts a #hb_feature_t into a `NULL`-terminated string in the format
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
@@ -972,7 +1025,7 @@ hb_feature_to_string (hb_feature_t *feature,
}
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
- memcpy (buf, s, len);
+ hb_memcpy (buf, s, len);
buf[len] = '\0';
}
@@ -1001,7 +1054,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
/**
* hb_variation_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
* @variation: (out): the #hb_variation_t to initialize with the parsed values
*
* Parses a string into a #hb_variation_t.
@@ -1014,7 +1067,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
* number. For example `wght=500`, or `slnt=-7.5`.
*
* Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
*
* Since: 1.4.2
*/
@@ -1035,17 +1088,58 @@ hb_variation_from_string (const char *str, int len,
}
if (variation)
- memset (variation, 0, sizeof (*variation));
+ hb_memset (variation, 0, sizeof (*variation));
return false;
}
+#ifndef HB_NO_SETLOCALE
+
+static inline void free_static_C_locale ();
+
+static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
+ hb_C_locale_lazy_loader_t>
+{
+ static hb_locale_t create ()
+ {
+ hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
+ if (!l)
+ return l;
+
+ hb_atexit (free_static_C_locale);
+
+ return l;
+ }
+ static void destroy (hb_locale_t l)
+ {
+ freelocale (l);
+ }
+ static hb_locale_t get_null ()
+ {
+ return (hb_locale_t) 0;
+ }
+} static_C_locale;
+
+static inline
+void free_static_C_locale ()
+{
+ static_C_locale.free_instance ();
+}
+
+static hb_locale_t
+get_C_locale ()
+{
+ return static_C_locale.get_unconst ();
+}
+
+#endif
+
/**
* hb_variation_to_string:
* @variation: an #hb_variation_t to convert
- * @buf: (array length=size) (out): output string
+ * @buf: (array length=size) (out caller-allocates): output string
* @size: the allocated size of @buf
*
- * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * Converts an #hb_variation_t into a `NULL`-terminated string in the format
* understood by hb_variation_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
@@ -1064,11 +1158,15 @@ hb_variation_to_string (hb_variation_t *variation,
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
+
+ hb_locale_t oldlocale HB_UNUSED;
+ oldlocale = hb_uselocale (get_C_locale ());
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
+ (void) hb_uselocale (oldlocale);
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
- memcpy (buf, s, len);
+ hb_memcpy (buf, s, len);
buf[len] = '\0';
}
diff --git a/src/hb-common.h b/src/hb-common.h
index 0384117a4..e92feb989 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -130,6 +130,16 @@ typedef union _hb_var_int_t {
int8_t i8[4];
} hb_var_int_t;
+typedef union _hb_var_num_t {
+ float f;
+ uint32_t u32;
+ int32_t i32;
+ uint16_t u16[2];
+ int16_t i16[2];
+ uint8_t u8[4];
+ int8_t i8[4];
+} hb_var_num_t;
+
/* hb_tag_t */
@@ -316,6 +326,9 @@ hb_language_to_string (hb_language_t language);
HB_EXTERN hb_language_t
hb_language_get_default (void);
+HB_EXTERN hb_bool_t
+hb_language_matches (hb_language_t language,
+ hb_language_t specific);
/**
* hb_script_t:
@@ -481,6 +494,9 @@ hb_language_get_default (void);
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
+ * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
+ * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
+ * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -697,6 +713,17 @@ typedef enum
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
+ /*
+ * Since 3.4.0
+ */
+ HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
+
+ /*
+ * Since 5.2.0
+ */
+ HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
+ HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
+
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
diff --git a/src/hb-config.hh b/src/hb-config.hh
index ad800f0f7..98b1e9d0c 100644
--- a/src/hb-config.hh
+++ b/src/hb-config.hh
@@ -35,6 +35,10 @@
#include "config.h"
#endif
+#ifndef HB_EXPERIMENTAL_API
+#define HB_NO_BEYOND_64K
+#define HB_NO_VAR_COMPOSITES
+#endif
#ifdef HB_TINY
#define HB_LEAN
@@ -55,6 +59,7 @@
#define HB_NO_ATEXIT
#define HB_NO_BUFFER_MESSAGE
#define HB_NO_BUFFER_SERIALIZE
+#define HB_NO_BUFFER_VERIFY
#define HB_NO_BITMAP
#define HB_NO_CFF
#define HB_NO_COLOR
@@ -63,9 +68,11 @@
#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
+#define HB_NO_LAYOUT_RARELY_USED
#define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH
#define HB_NO_META
@@ -78,26 +85,41 @@
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_STYLE
#define HB_NO_SUBSET_LAYOUT
+#define HB_NO_VERTICAL
#define HB_NO_VAR
#endif
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
+#define HB_NO_BORING_EXPANSION
#endif
-#ifdef HAVE_CONFIG_OVERRIDE_H
-#include "config-override.h"
+#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
+#ifndef HB_CONFIG_OVERRIDE_H
+#define HB_CONFIG_OVERRIDE_H "config-override.h"
+#endif
+#include HB_CONFIG_OVERRIDE_H
#endif
/* Closure of options. */
+#ifdef HB_NO_BORING_EXPANSION
+#define HB_NO_BEYOND_64K
+#define HB_NO_AVAR2
+#endif
+
#ifdef HB_DISABLE_DEPRECATED
#define HB_IF_NOT_DEPRECATED(x)
#else
#define HB_IF_NOT_DEPRECATED(x) x
#endif
+#ifdef HB_NO_SHAPER
+#define HB_NO_OT_SHAPE
+#define HB_NO_AAT_SHAPE
+#endif
+
#ifdef HB_NO_AAT
#define HB_NO_OT_NAME_LANGUAGE_AAT
#define HB_NO_AAT_SHAPE
@@ -140,10 +162,11 @@
#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
+#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#endif
#ifdef NDEBUG
@@ -158,5 +181,9 @@
#endif
#endif
+#ifdef HB_OPTIMIZE_SIZE
+#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#endif
+
#endif /* HB_CONFIG_HH */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 4b6c67c1e..4267e0e13 100644
--- a/src/hb-coretext.cc
+++ b/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,
@@ -347,10 +347,13 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
- CFDictionarySetValue (variations,
- CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag),
- CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i])
- );
+ float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
+
+ CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
+ CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
+ CFDictionarySetValue (variations, tag_number, value_number);
+ CFRelease (tag_number);
+ CFRelease (value_number);
}
CFDictionaryRef attributes =
@@ -379,37 +382,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 +427,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;
}
@@ -481,8 +453,8 @@ struct active_feature_t {
a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
0;
}
- bool operator== (const active_feature_t *f) {
- return cmp (this, f) == 0;
+ bool operator== (const active_feature_t& f) const {
+ return cmp (this, &f) == 0;
}
};
@@ -516,7 +488,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;
@@ -677,9 +649,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
{
active_features.push (event->feature);
} else {
- active_feature_t *feature = active_features.find (&event->feature);
+ active_feature_t *feature = active_features.lsearch (event->feature);
if (feature)
- active_features.remove (feature - active_features.arrayZ);
+ active_features.remove_ordered (feature - active_features.arrayZ);
}
}
}
@@ -897,7 +869,7 @@ resize_and_retry:
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
buffer->len = 0;
- uint32_t status_and = ~0, status_or = 0;
+ uint32_t status_or = 0;
CGFloat advances_so_far = 0;
/* For right-to-left runs, CoreText returns the glyphs positioned such that
* any trailing whitespace is to the left of (0,0). Adjust coordinate system
@@ -918,7 +890,6 @@ resize_and_retry:
CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
CTRunStatus run_status = CTRunGetStatus (run);
status_or |= run_status;
- status_and &= run_status;
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
@@ -1107,7 +1078,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++;
@@ -1123,7 +1095,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++;
@@ -1140,21 +1113,6 @@ resize_and_retry:
buffer->len += num_glyphs;
}
- /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
- * or if it does, it doesn't respect it. So we get runs with wrong
- * directions. As such, disable the assert... It wouldn't crash, but
- * cursoring will be off...
- *
- * https://crbug.com/419769
- */
- if (false)
- {
- /* Make sure all runs had the expected direction. */
- HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
- assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
- assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
- }
-
buffer->clear_positions ();
unsigned int count = buffer->len;
@@ -1167,7 +1125,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++)
@@ -1176,7 +1134,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;
@@ -1189,7 +1147,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))
@@ -1213,7 +1172,12 @@ resize_and_retry:
}
}
- buffer->unsafe_to_break_all ();
+ /* 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 ();
#undef FAIL
diff --git a/src/hb-cplusplus.hh b/src/hb-cplusplus.hh
new file mode 100644
index 000000000..a210ab796
--- /dev/null
+++ b/src/hb-cplusplus.hh
@@ -0,0 +1,221 @@
+/*
+ * 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 () const { return p; }
+ bool operator == (const shared_ptr &o) const { return p == o.p; }
+ bool operator != (const shared_ptr &o) const { 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) (const 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
+
+
+#ifdef HB_SUBSET_H
+
+#define HB_DEFINE_VTABLE(name) \
+ template<> \
+ struct vtable<hb_##name##_t> \
+ : vtable_t<hb_##name##_t, \
+ nullptr, \
+ &hb_##name##_reference, \
+ &hb_##name##_destroy, \
+ &hb_##name##_set_user_data, \
+ &hb_##name##_get_user_data> {}
+
+
+HB_DEFINE_VTABLE (subset_input);
+HB_DEFINE_VTABLE (subset_plan);
+
+#undef HB_DEFINE_VTABLE
+
+#endif
+
+
+} // namespace hb
+
+/* Workaround for GCC < 7, see:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+ * https://stackoverflow.com/a/25594741 */
+namespace std {
+
+
+template<typename T>
+struct 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 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;
+ }
+};
+
+
+} // namespace std
+
+#endif /* __cplusplus */
+
+#endif /* HB_CPLUSPLUS_HH */
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index 3ac7440e8..cbe13e521 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -67,12 +67,12 @@ hb_options ()
#endif
/* Make a local copy, so we can access bitfield threadsafely. */
hb_options_union_t u;
- u.i = _hb_options.get_relaxed ();
+ u.i = _hb_options;
if (unlikely (!u.i))
{
_hb_options_init ();
- u.i = _hb_options.get_relaxed ();
+ u.i = _hb_options;
}
return u.opts;
@@ -460,4 +460,9 @@ struct hb_no_trace_t {
#endif
+#ifndef HB_BUFFER_MESSAGE_MORE
+#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
+#endif
+
+
#endif /* HB_DEBUG_HH */
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index a130d77f7..333dc3cd4 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -93,7 +93,7 @@ HB_BEGIN_DECLS
* This method should retrieve the glyph ID for a specified Unicode code point
* font, with an optional variation selector.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
* Deprecated: 1.2.3
*
**/
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index db7b53b25..de05b7d87 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -44,7 +44,7 @@
**/
/* Declare object creator for dynamic support of DWRITE */
-typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
@@ -273,17 +273,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;
}
@@ -794,6 +789,9 @@ retry_getglyphs:
if (isRightToLeft) hb_buffer_reverse (buffer);
+ buffer->clear_glyph_flags ();
+ buffer->unsafe_to_break ();
+
delete [] clusterMap;
delete [] glyphIndices;
delete [] textProperties;
diff --git a/src/hb-draw.cc b/src/hb-draw.cc
index c0af6ce01..72c203f24 100644
--- a/src/hb-draw.cc
+++ b/src/hb-draw.cc
@@ -25,237 +25,373 @@
#include "hb.hh"
#ifndef HB_NO_DRAW
-#ifdef HB_EXPERIMENTAL_API
#include "hb-draw.hh"
-#include "hb-ot.h"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
-#include "hb-ot-cff2-table.hh"
/**
- * hb_draw_funcs_set_move_to_func:
- * @funcs: draw functions object
- * @move_to: move-to callback
+ * SECTION:hb-draw
+ * @title: hb-draw
+ * @short_description: Glyph drawing
+ * @include: hb.h
*
- * Sets move-to callback to the draw functions object.
- *
- * Since: EXPERIMENTAL
+ * Functions for drawing (extracting) glyph shapes.
**/
-void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
- hb_draw_move_to_func_t move_to)
+
+static void
+hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+ hb_draw_state_t *st HB_UNUSED,
+ float to_x HB_UNUSED, float to_y HB_UNUSED,
+ void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+ hb_draw_state_t *st HB_UNUSED,
+ float to_x HB_UNUSED, float to_y HB_UNUSED,
+ void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *user_data HB_UNUSED)
+{
+#define HB_ONE_THIRD 0.33333333f
+ dfuncs->emit_cubic_to (draw_data, *st,
+ (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
+hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+ hb_draw_state_t *st HB_UNUSED,
+ float control1_x HB_UNUSED, float control1_y HB_UNUSED,
+ float control2_x HB_UNUSED, float control2_y HB_UNUSED,
+ float to_x HB_UNUSED, float to_y HB_UNUSED,
+ void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+ hb_draw_state_t *st HB_UNUSED,
+ void *user_data HB_UNUSED) {}
+
+
+static bool
+_hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs,
+ bool func_is_null,
+ void **user_data,
+ hb_destroy_func_t *destroy)
+{
+ if (hb_object_is_immutable (dfuncs))
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ return false;
+ }
+
+ if (func_is_null)
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ *destroy = nullptr;
+ *user_data = nullptr;
+ }
+
+ return true;
+}
+
+static bool
+_hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs,
+ void *user_data,
+ hb_destroy_func_t destroy)
{
- if (unlikely (hb_object_is_immutable (funcs))) return;
- funcs->move_to = move_to;
+ 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;
+ }
+
+ return true;
+
+fail:
+ if (destroy)
+ (destroy) (user_data);
+ return false;
}
+#define HB_DRAW_FUNC_IMPLEMENT(name) \
+ \
+void \
+hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \
+ hb_draw_##name##_func_t func, \
+ void *user_data, \
+ hb_destroy_func_t destroy) \
+{ \
+ if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\
+ return; \
+ \
+ if (dfuncs->destroy && dfuncs->destroy->name) \
+ dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \
+ \
+ if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \
+ return; \
+ \
+ if (func) \
+ dfuncs->func.name = func; \
+ else \
+ dfuncs->func.name = hb_draw_##name##_nil; \
+ \
+ if (dfuncs->user_data) \
+ dfuncs->user_data->name = user_data; \
+ if (dfuncs->destroy) \
+ dfuncs->destroy->name = destroy; \
+}
+
+HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+
/**
- * hb_draw_funcs_set_line_to_func:
- * @funcs: draw functions object
- * @line_to: line-to callback
+ * hb_draw_funcs_create:
+ *
+ * Creates a new draw callbacks object.
*
- * Sets line-to callback to the draw functions object.
+ * Return value: (transfer full):
+ * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
+ * reference count should be released with hb_draw_funcs_destroy when you are
+ * done using the #hb_draw_funcs_t. This function never returns `NULL`. If
+ * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
+ * be returned.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
- hb_draw_line_to_func_t line_to)
+hb_draw_funcs_t *
+hb_draw_funcs_create ()
{
- if (unlikely (hb_object_is_immutable (funcs))) return;
- funcs->line_to = line_to;
+ hb_draw_funcs_t *dfuncs;
+ if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ())))
+ return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+
+ dfuncs->func = Null (hb_draw_funcs_t).func;
+
+ return dfuncs;
}
+DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
+{
+ HB_OBJECT_HEADER_STATIC,
+
+ {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil,
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+ }
+};
+
+
/**
- * hb_draw_funcs_set_quadratic_to_func:
- * @funcs: draw functions object
- * @move_to: quadratic-to callback
+ * hb_draw_funcs_reference: (skip)
+ * @dfuncs: draw functions
+ *
+ * Increases the reference count on @dfuncs by one. This prevents @buffer from
+ * being destroyed until a matching call to hb_draw_funcs_destroy() is made.
*
- * Sets quadratic-to callback to the draw functions object.
+ * Return value: (transfer full):
+ * The referenced #hb_draw_funcs_t.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
- hb_draw_quadratic_to_func_t quadratic_to)
+hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs)
{
- if (unlikely (hb_object_is_immutable (funcs))) return;
- funcs->quadratic_to = quadratic_to;
- funcs->is_quadratic_to_set = true;
+ return hb_object_reference (dfuncs);
}
/**
- * hb_draw_funcs_set_cubic_to_func:
- * @funcs: draw functions
- * @cubic_to: cubic-to callback
+ * hb_draw_funcs_destroy: (skip)
+ * @dfuncs: draw functions
*
- * Sets cubic-to callback to the draw functions object.
+ * Deallocate the @dfuncs.
+ * Decreases the reference count on @dfuncs by one. If the result is zero, then
+ * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference().
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
- hb_draw_cubic_to_func_t cubic_to)
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
{
- if (unlikely (hb_object_is_immutable (funcs))) return;
- funcs->cubic_to = cubic_to;
+ if (!hb_object_destroy (dfuncs)) return;
+
+ if (dfuncs->destroy)
+ {
+#define HB_DRAW_FUNC_IMPLEMENT(name) \
+ 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->destroy);
+ hb_free (dfuncs->user_data);
+
+ hb_free (dfuncs);
}
/**
- * hb_draw_funcs_set_close_path_func:
- * @funcs: draw functions object
- * @close_path: close-path callback
+ * hb_draw_funcs_make_immutable:
+ * @dfuncs: draw functions
*
- * Sets close-path callback to the draw functions object.
+ * Makes @dfuncs object immutable.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
- hb_draw_close_path_func_t close_path)
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
{
- if (unlikely (hb_object_is_immutable (funcs))) return;
- funcs->close_path = close_path;
-}
-
-static void
-_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
- hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
- void *user_data HB_UNUSED) {}
-
-static void
-_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
- hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
- hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
- void *user_data HB_UNUSED) {}
+ if (hb_object_is_immutable (dfuncs))
+ return;
-static void
-_close_path_nil (void *user_data HB_UNUSED) {}
+ hb_object_make_immutable (dfuncs);
+}
/**
- * hb_draw_funcs_create:
+ * hb_draw_funcs_is_immutable:
+ * @dfuncs: draw functions
*
- * Creates a new draw callbacks object.
+ * Checks whether @dfuncs is immutable.
+ *
+ * Return value: `true` if @dfuncs is immutable, `false` otherwise
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-hb_draw_funcs_t *
-hb_draw_funcs_create ()
+hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs)
{
- hb_draw_funcs_t *funcs;
- if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
- return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
-
- funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
- funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
- funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
- funcs->is_quadratic_to_set = false;
- funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
- funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
- return funcs;
+ return hb_object_is_immutable (dfuncs);
}
+
/**
- * hb_draw_funcs_reference:
- * @funcs: draw functions
+ * hb_draw_move_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
*
- * Add to callbacks object refcount.
+ * Perform a "move-to" draw operation.
*
- * Returns: The same object.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
+void
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y)
{
- return hb_object_reference (funcs);
+ dfuncs->move_to (draw_data, *st,
+ to_x, to_y);
}
/**
- * hb_draw_funcs_destroy:
- * @funcs: draw functions
+ * hb_draw_line_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
*
- * Decreases refcount of callbacks object and deletes the object if it reaches
- * to zero.
+ * Perform a "line-to" draw operation.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y)
{
- if (!hb_object_destroy (funcs)) return;
-
- hb_free (funcs);
+ dfuncs->line_to (draw_data, *st,
+ to_x, to_y);
}
/**
- * hb_draw_funcs_make_immutable:
- * @funcs: draw functions
+ * hb_draw_quadratic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
*
- * Makes funcs object immutable.
+ * Perform a "quadratic-to" draw operation.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y)
{
- if (hb_object_is_immutable (funcs))
- return;
-
- hb_object_make_immutable (funcs);
+ dfuncs->quadratic_to (draw_data, *st,
+ control_x, control_y,
+ to_x, to_y);
}
/**
- * hb_draw_funcs_is_immutable:
- * @funcs: draw functions
+ * hb_draw_cubic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
*
- * Checks whether funcs is immutable.
+ * Perform a "cubic-to" draw operation.
*
- * Returns: If is immutable.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
+void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y)
{
- return hb_object_is_immutable (funcs);
+ dfuncs->cubic_to (draw_data, *st,
+ control1_x, control1_y,
+ control2_x, control2_y,
+ to_x, to_y);
}
/**
- * hb_font_draw_glyph:
- * @font: a font object
- * @glyph: a glyph id
- * @funcs: draw callbacks object
- * @user_data: parameter you like be passed to the callbacks when are called
+ * hb_draw_close_path:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
*
- * Draw a glyph.
+ * Perform a "close-path" draw operation.
*
- * Returns: Whether the font had the glyph and the operation completed successfully.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
-hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
- const hb_draw_funcs_t *funcs,
- void *user_data)
+void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st)
{
- if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
- glyph >= font->face->get_num_glyphs ()))
- return false;
-
- draw_helper_t draw_helper (funcs, user_data);
- if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
-#ifndef HB_NO_CFF
- if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
- if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
-#endif
-
- return false;
+ dfuncs->close_path (draw_data, *st);
}
-#endif
+
#endif
diff --git a/src/hb-draw.h b/src/hb-draw.h
index bddc87639..c45a53212 100644
--- a/src/hb-draw.h
+++ b/src/hb-draw.h
@@ -33,65 +33,292 @@
HB_BEGIN_DECLS
-#ifdef HB_EXPERIMENTAL_API
-typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
- hb_position_t to_x, hb_position_t to_y,
- void *user_data);
-typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
- hb_position_t control2_x, hb_position_t control2_y,
- hb_position_t to_x, hb_position_t to_y,
- void *user_data);
-typedef void (*hb_draw_close_path_func_t) (void *user_data);
+
+/**
+ * hb_draw_state_t
+ * @path_open: Whether there is an open path
+ * @path_start_x: X component of the start of current path
+ * @path_start_y: Y component of the start of current path
+ * @current_x: X component of current point
+ * @current_y: Y component of current point
+ *
+ * Current drawing state.
+ *
+ * Since: 4.0.0
+ **/
+typedef struct hb_draw_state_t {
+ hb_bool_t path_open;
+
+ float path_start_x;
+ float path_start_y;
+
+ float current_x;
+ float current_y;
+
+ /*< private >*/
+ hb_var_num_t reserved1;
+ hb_var_num_t reserved2;
+ hb_var_num_t reserved3;
+ hb_var_num_t reserved4;
+ hb_var_num_t reserved5;
+ hb_var_num_t reserved6;
+ hb_var_num_t reserved7;
+} hb_draw_state_t;
+
+/**
+ * HB_DRAW_STATE_DEFAULT:
+ *
+ * The default #hb_draw_state_t at the start of glyph drawing.
+ */
+#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
+
/**
* hb_draw_funcs_t:
*
* Glyph draw callbacks.
*
- * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we
- * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
+ * #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and
+ * #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate
+ * #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the
+ * callback isn't defined.
*
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
**/
+
typedef struct hb_draw_funcs_t hb_draw_funcs_t;
+
+/**
+ * hb_draw_move_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data);
+
+/**
+ * hb_draw_line_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data);
+
+/**
+ * hb_draw_quadratic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *user_data);
+
+/**
+ * hb_draw_cubic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *user_data);
+
+/**
+ * hb_draw_close_path_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ void *user_data);
+
+/**
+ * hb_draw_funcs_set_move_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): move-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets move-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
HB_EXTERN void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
- hb_draw_move_to_func_t move_to);
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *dfuncs,
+ hb_draw_move_to_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_draw_funcs_set_line_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): line-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets line-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
HB_EXTERN void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
- hb_draw_line_to_func_t line_to);
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *dfuncs,
+ hb_draw_line_to_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_draw_funcs_set_quadratic_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets quadratic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
HB_EXTERN void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
- hb_draw_quadratic_to_func_t quadratic_to);
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *dfuncs,
+ hb_draw_quadratic_to_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_draw_funcs_set_cubic_to_func:
+ * @dfuncs: draw functions
+ * @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets cubic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
HB_EXTERN void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
- hb_draw_cubic_to_func_t cubic_to);
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *dfuncs,
+ hb_draw_cubic_to_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_draw_funcs_set_close_path_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): close-path callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets close-path callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
HB_EXTERN void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
- hb_draw_close_path_func_t close_path);
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs,
+ hb_draw_close_path_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void);
HB_EXTERN hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
HB_EXTERN hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
-#endif
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs);
+
+
+HB_EXTERN void
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+ hb_draw_state_t *st);
+
HB_END_DECLS
diff --git a/src/hb-draw.hh b/src/hb-draw.hh
index 2aa0a5b4d..768f51a87 100644
--- a/src/hb-draw.hh
+++ b/src/hb-draw.hh
@@ -27,113 +27,205 @@
#include "hb.hh"
-#ifdef HB_EXPERIMENTAL_API
-struct hb_draw_funcs_t
-{
- hb_object_header_t header;
- hb_draw_move_to_func_t move_to;
- hb_draw_line_to_func_t line_to;
- hb_draw_quadratic_to_func_t quadratic_to;
- bool is_quadratic_to_set;
- hb_draw_cubic_to_func_t cubic_to;
- hb_draw_close_path_func_t close_path;
-};
+/*
+ * hb_draw_funcs_t
+ */
+
+#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \
+ HB_DRAW_FUNC_IMPLEMENT (move_to) \
+ HB_DRAW_FUNC_IMPLEMENT (line_to) \
+ HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \
+ HB_DRAW_FUNC_IMPLEMENT (cubic_to) \
+ HB_DRAW_FUNC_IMPLEMENT (close_path) \
+ /* ^--- Add new callbacks here */
-struct draw_helper_t
+struct hb_draw_funcs_t
{
- draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
- {
- funcs = funcs_;
- user_data = user_data_;
- path_open = false;
- path_start_x = current_x = path_start_y = current_y = 0;
- }
- ~draw_helper_t () { end_path (); }
+ hb_object_header_t header;
- void move_to (hb_position_t x, hb_position_t y)
+ struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name;
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+ } func;
+
+ struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) void *name;
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+ } *user_data;
+
+ struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+ } *destroy;
+
+ void emit_move_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
+ { func.move_to (this, draw_data, &st,
+ to_x, to_y,
+ !user_data ? 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 ? 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 ? 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,
+ float to_x, float to_y)
+ { func.cubic_to (this, draw_data, &st,
+ control1_x, control1_y,
+ control2_x, control2_y,
+ to_x, to_y,
+ !user_data ? 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 ? nullptr : user_data->close_path); }
+
+
+ void move_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (path_open) end_path ();
- current_x = path_start_x = x;
- current_y = path_start_y = y;
+ if (st.path_open) close_path (draw_data, st);
+ st.current_x = to_x;
+ st.current_y = to_y;
}
- void line_to (hb_position_t x, hb_position_t y)
+ void line_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (equal_to_current (x, y)) return;
- if (!path_open) start_path ();
- funcs->line_to (x, y, user_data);
- current_x = x;
- current_y = y;
+ if (!st.path_open) start_path (draw_data, st);
+ emit_line_to (draw_data, st, to_x, to_y);
+ st.current_x = to_x;
+ st.current_y = to_y;
}
void
- quadratic_to (hb_position_t control_x, hb_position_t control_y,
- hb_position_t to_x, hb_position_t to_y)
+ quadratic_to (void *draw_data, hb_draw_state_t &st,
+ float control_x, float control_y,
+ float to_x, float to_y)
{
- if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
- return;
- if (!path_open) start_path ();
- if (funcs->is_quadratic_to_set)
- funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
- else
- funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
- roundf ((current_y + 2.f * control_y) / 3.f),
- roundf ((to_x + 2.f * control_x) / 3.f),
- roundf ((to_y + 2.f * control_y) / 3.f),
- to_x, to_y, user_data);
- current_x = to_x;
- current_y = to_y;
+ if (!st.path_open) start_path (draw_data, st);
+ emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
+ st.current_x = to_x;
+ st.current_y = to_y;
}
void
- cubic_to (hb_position_t control1_x, hb_position_t control1_y,
- hb_position_t control2_x, hb_position_t control2_y,
- hb_position_t to_x, hb_position_t to_y)
+ cubic_to (void *draw_data, hb_draw_state_t &st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y)
{
- if (equal_to_current (control1_x, control1_y) &&
- equal_to_current (control2_x, control2_y) &&
- equal_to_current (to_x, to_y))
- return;
- if (!path_open) start_path ();
- funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
- current_x = to_x;
- current_y = to_y;
+ if (!st.path_open) start_path (draw_data, st);
+ emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+ st.current_x = to_x;
+ st.current_y = to_y;
}
- void end_path ()
+ void
+ close_path (void *draw_data, hb_draw_state_t &st)
{
- if (path_open)
+ if (st.path_open)
{
- if ((path_start_x != current_x) || (path_start_y != current_y))
- funcs->line_to (path_start_x, path_start_y, user_data);
- funcs->close_path (user_data);
+ if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
+ emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
+ emit_close_path (draw_data, st);
}
- path_open = false;
- path_start_x = current_x = path_start_y = current_y = 0;
+ st.path_open = false;
+ st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0;
}
protected:
- bool equal_to_current (hb_position_t x, hb_position_t y)
- { return current_x == x && current_y == y; }
- void start_path ()
+ void start_path (void *draw_data, hb_draw_state_t &st)
{
- if (path_open) end_path ();
- path_open = true;
- funcs->move_to (path_start_x, path_start_y, user_data);
+ assert (!st.path_open);
+ emit_move_to (draw_data, st, st.current_x, st.current_y);
+ st.path_open = true;
+ st.path_start_x = st.current_x;
+ st.path_start_y = st.current_y;
}
+};
+DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
- hb_position_t path_start_x;
- hb_position_t path_start_y;
+struct hb_draw_session_t
+{
+ hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
+ : slant {slant_}, not_slanted {slant == 0.f},
+ funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
+ {}
- hb_position_t current_x;
- hb_position_t current_y;
+ ~hb_draw_session_t () { close_path (); }
- bool path_open;
- const hb_draw_funcs_t *funcs;
- void *user_data;
+ void move_to (float to_x, float to_y)
+ {
+ if (likely (not_slanted))
+ funcs->move_to (draw_data, st,
+ to_x, to_y);
+ else
+ funcs->move_to (draw_data, st,
+ to_x + to_y * slant, to_y);
+ }
+ void line_to (float to_x, float to_y)
+ {
+ if (likely (not_slanted))
+ funcs->line_to (draw_data, st,
+ to_x, to_y);
+ else
+ funcs->line_to (draw_data, st,
+ to_x + to_y * slant, to_y);
+ }
+ void
+ quadratic_to (float control_x, float control_y,
+ float to_x, float to_y)
+ {
+ if (likely (not_slanted))
+ funcs->quadratic_to (draw_data, st,
+ control_x, control_y,
+ to_x, to_y);
+ else
+ funcs->quadratic_to (draw_data, st,
+ control_x + control_y * slant, control_y,
+ to_x + to_y * slant, to_y);
+ }
+ void
+ cubic_to (float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y)
+ {
+ if (likely (not_slanted))
+ funcs->cubic_to (draw_data, st,
+ control1_x, control1_y,
+ control2_x, control2_y,
+ to_x, to_y);
+ else
+ funcs->cubic_to (draw_data, st,
+ control1_x + control1_y * slant, control1_y,
+ control2_x + control2_y * slant, control2_y,
+ to_x + to_y * slant, to_y);
+ }
+ void close_path ()
+ {
+ funcs->close_path (draw_data, st);
+ }
+
+ protected:
+ float slant;
+ bool not_slanted;
+ hb_draw_funcs_t *funcs;
+ void *draw_data;
+ hb_draw_state_t st;
};
-#endif
#endif /* HB_DRAW_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 2c0087370..8b4b635c7 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -132,7 +132,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
face->user_data = user_data;
face->destroy = destroy;
- face->num_glyphs.set_relaxed (-1);
+ face->num_glyphs = -1;
face->data.init0 (face);
face->table.init0 (face);
@@ -143,7 +143,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
typedef struct hb_face_for_data_closure_t {
hb_blob_t *blob;
- unsigned int index;
+ uint16_t index;
} hb_face_for_data_closure_t;
static hb_face_for_data_closure_t *
@@ -156,7 +156,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
return nullptr;
closure->blob = blob;
- closure->index = index;
+ closure->index = (uint16_t) (index & 0xFFFFu);
return closure;
}
@@ -190,14 +190,24 @@ _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
*
* Constructs a new face object from the specified blob and
- * a face index into that blob. This is used for blobs of
- * file formats such as Dfont and TTC that can contain more
- * than one face.
+ * a face index into that blob.
+ *
+ * The face index is used for blobs of file formats such as TTC and
+ * and DFont that can contain more than one face. Face indices within
+ * such collections are zero-based.
+ *
+ * <note>Note: If the blob font format is not a collection, @index
+ * is ignored. Otherwise, only the lower 16-bits of @index are used.
+ * The unmodified @index can be accessed via hb_face_get_index().</note>
+ *
+ * <note>Note: The high 16-bits of @index, if non-zero, are used by
+ * hb_font_create() to load named-instances in variable fonts. See
+ * hb_font_create() for details.</note>
*
* Return value: (transfer full): The new face object
*
@@ -278,6 +288,7 @@ hb_face_destroy (hb_face_t *face)
{
if (!hb_object_destroy (face)) return;
+#ifndef HB_NO_SHAPER
for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
{
hb_face_t::plan_node_t *next = node->next;
@@ -285,6 +296,7 @@ hb_face_destroy (hb_face_t *face)
hb_free (node);
node = next;
}
+#endif
face->data.fini ();
face->table.fini ();
@@ -305,7 +317,7 @@ hb_face_destroy (hb_face_t *face)
*
* Attaches a user-data key/data pair to the given face object.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -361,7 +373,7 @@ hb_face_make_immutable (hb_face_t *face)
*
* Tests whether the given face object is immutable.
*
- * Return value: %true is @face is immutable, %false otherwise
+ * Return value: `true` is @face is immutable, `false` otherwise
*
* Since: 0.9.2
**/
@@ -420,7 +432,8 @@ hb_face_reference_blob (hb_face_t *face)
* Assigns the specified face-index to @face. Fails if the
* face is immutable.
*
- * <note>Note: face indices within a collection are zero-based.</note>
+ * <note>Note: changing the index has no effect on the face itself
+ * This only changes the value returned by hb_face_get_index().</note>
*
* Since: 0.9.2
**/
@@ -468,7 +481,7 @@ hb_face_set_upem (hb_face_t *face,
if (hb_object_is_immutable (face))
return;
- face->upem.set_relaxed (upem);
+ face->upem = upem;
}
/**
@@ -503,7 +516,7 @@ hb_face_set_glyph_count (hb_face_t *face,
if (hb_object_is_immutable (face))
return;
- face->num_glyphs.set_relaxed (glyph_count);
+ face->num_glyphs = glyph_count;
}
/**
@@ -622,20 +635,29 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
* face-builder: A face that has add_table().
*/
+struct face_table_info_t
+{
+ hb_blob_t* data;
+ signed order;
+};
+
struct hb_face_builder_data_t
{
- hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
+ hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
};
static int compare_entries (const void* pa, const void* pb)
{
- const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
- const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
+ const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
+ const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */
- if (a.second->length != b.second->length)
- return a.second->length < b.second->length ? -1 : +1;
+ if (a.second.order != b.second.order)
+ return a.second.order < b.second.order ? -1 : +1;
+
+ if (a.second.data->length != b.second.data->length)
+ return a.second.data->length < b.second.data->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
}
@@ -657,8 +679,8 @@ _hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
- for (hb_blob_t* b : data->tables.values())
- hb_blob_destroy (b);
+ for (auto info : data->tables.values())
+ hb_blob_destroy (info.data);
data->tables.fini ();
@@ -672,8 +694,8 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12;
- for (hb_blob_t* b : data->tables.values())
- face_length += hb_ceil_to_4 (hb_blob_get_length (b));
+ for (auto info : data->tables.values())
+ face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf))
@@ -688,7 +710,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
// Sort the tags so that produced face is deterministic.
- hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
+ hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ()))
{
@@ -697,7 +719,13 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
}
sorted_entries.qsort (compare_entries);
- bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
+
+ bool ret = f->serialize_single (&c,
+ sfnt_tag,
+ + sorted_entries.iter()
+ | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
+ return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
+ }));
c.end_serialize ();
@@ -718,7 +746,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
if (!tag)
return _hb_face_builder_data_reference_blob (data);
- return hb_blob_reference (data->tables[tag]);
+ return hb_blob_reference (data->tables[tag].data);
}
@@ -758,16 +786,16 @@ hb_face_builder_create ()
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
- if (tag == HB_MAP_VALUE_INVALID)
+ if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
- if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+ if (tag == HB_MAP_VALUE_INVALID)
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
- hb_blob_t* previous = data->tables.get (tag);
- if (!data->tables.set (tag, hb_blob_reference (blob)))
+ hb_blob_t* previous = data->tables.get (tag).data;
+ if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
{
hb_blob_destroy (blob);
return false;
@@ -776,3 +804,39 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_blob_destroy (previous);
return true;
}
+
+/**
+ * hb_face_builder_sort_tables:
+ * @face: A face object created with hb_face_builder_create()
+ * @tags: (array zero-terminated=1): ordered list of table tags terminated by
+ * %HB_TAG_NONE
+ *
+ * Set the ordering of tables for serialization. Any tables not
+ * specified in the tags list will be ordered after the tables in
+ * tags, ordered by the default sort ordering.
+ *
+ * Since: 5.3.0
+ **/
+void
+hb_face_builder_sort_tables (hb_face_t *face,
+ const hb_tag_t *tags)
+{
+ if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+ return;
+
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+ // Sort all unspecified tables after any specified tables.
+ for (auto& info : data->tables.values_ref())
+ info.order = (unsigned) -1;
+
+ signed order = 0;
+ for (const hb_tag_t* tag = tags;
+ *tag;
+ tag++)
+ {
+ face_table_info_t* info;
+ if (!data->tables.has (*tag, &info)) continue;
+ info->order = order++;
+ }
+}
diff --git a/src/hb-face.h b/src/hb-face.h
index 6ef2f8b88..38e7104af 100644
--- a/src/hb-face.h
+++ b/src/hb-face.h
@@ -171,6 +171,10 @@ hb_face_builder_add_table (hb_face_t *face,
hb_tag_t tag,
hb_blob_t *blob);
+HB_EXTERN void
+hb_face_builder_sort_tables (hb_face_t *face,
+ const hb_tag_t *tags);
+
HB_END_DECLS
diff --git a/src/hb-face.hh b/src/hb-face.hh
index 765f27285..1bf0606e5 100644
--- a/src/hb-face.hh
+++ b/src/hb-face.hh
@@ -65,7 +65,9 @@ struct hb_face_t
hb_shape_plan_t *shape_plan;
plan_node_t *next;
};
+#ifndef HB_NO_SHAPER
hb_atomic_ptr_t<plan_node_t> shape_plans;
+#endif
hb_blob_t *reference_table (hb_tag_t tag) const
{
@@ -83,7 +85,7 @@ struct hb_face_t
unsigned int get_upem () const
{
- unsigned int ret = upem.get_relaxed ();
+ unsigned int ret = upem;
if (unlikely (!ret))
{
return load_upem ();
@@ -93,7 +95,7 @@ struct hb_face_t
unsigned int get_num_glyphs () const
{
- unsigned int ret = num_glyphs.get_relaxed ();
+ unsigned int ret = num_glyphs;
if (unlikely (ret == UINT_MAX))
return load_num_glyphs ();
return ret;
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index c5b7c2c23..c54ad8764 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *features HB_UNUSED,
unsigned int num_features HB_UNUSED)
{
- /* TODO
- *
- * - Apply fallback kern.
- * - Handle Variation Selectors?
- * - Apply normalization?
- *
- * This will make the fallback shaper into a dumb "TrueType"
- * shaper which many people unfortunately still request.
- */
-
hb_codepoint_t space;
bool has_space = (bool) font->get_nominal_glyph (' ', &space);
@@ -117,7 +107,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
if (HB_DIRECTION_IS_BACKWARD (direction))
hb_buffer_reverse (buffer);
- buffer->safe_to_break_all ();
+ buffer->clear_glyph_flags ();
return true;
}
diff --git a/src/hb-features.h.in b/src/hb-features.h.in
new file mode 100644
index 000000000..30ebf6519
--- /dev/null
+++ b/src/hb-features.h.in
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ */
+
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_FEATURES_H
+#define HB_FEATURES_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+/**
+ * HB_HAS_FREETYPE:
+ *
+ * Defined if Harfbuzz has been built with Freetype support.
+ */
+#mesondefine HB_HAS_FREETYPE
+
+/**
+ * HB_HAS_GDI:
+ *
+ * Defined if Harfbuzz has been built with GDI support.
+ */
+#mesondefine HB_HAS_GDI
+
+/**
+ * HB_HAS_GRAPHITE:
+ *
+ * Defined if Harfbuzz has been built with Graphite support.
+ */
+#mesondefine HB_HAS_GRAPHITE
+
+/**
+ * HB_HAS_GLIB:
+ *
+ * Defined if Harfbuzz has been built with GLib support.
+ */
+#mesondefine HB_HAS_GLIB
+
+/**
+ * HB_HAS_UNISCRIBE:
+ *
+ * Defined if Harfbuzz has been built with Uniscribe support.
+ */
+#mesondefine HB_HAS_UNISCRIBE
+
+/**
+ * HB_HAS_DIRECTWRITE:
+ *
+ * Defined if Harfbuzz has been built with DirectWrite support.
+ */
+#mesondefine HB_HAS_DIRECTWRITE
+
+/**
+ * HB_HAS_CORETEXT:
+ *
+ * Defined if Harfbuzz has been built with CoreText support.
+ */
+#mesondefine HB_HAS_CORETEXT
+
+/**
+ * HB_HAS_ICU:
+ *
+ * Defined if Harfbuzz has been built with ICU support.
+ */
+#mesondefine HB_HAS_ICU
+
+
+HB_END_DECLS
+
+#endif /* HB_FEATURES_H */
diff --git a/src/hb-font.cc b/src/hb-font.cc
index fa8da9639..0ce3e2608 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -29,6 +29,7 @@
#include "hb.hh"
#include "hb-font.hh"
+#include "hb-draw.hh"
#include "hb-machinery.hh"
#include "hb-ot.h"
@@ -70,7 +71,7 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -95,7 +96,7 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -408,7 +409,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
return false;
}
@@ -501,20 +502,149 @@ hb_font_get_glyph_from_name_default (hb_font_t *font,
return font->parent->get_glyph_from_name (name, len, glyph);
}
-DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
+static void
+hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs,
+ void *draw_data,
+ void *user_data HB_UNUSED)
+{
+}
+
+
+typedef struct hb_font_get_glyph_shape_default_adaptor_t {
+ hb_draw_funcs_t *draw_funcs;
+ void *draw_data;
+ float x_scale;
+ float y_scale;
+ float slant;
+} hb_font_get_glyph_shape_default_adaptor_t;
+
+static void
+hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
+ void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data HB_UNUSED)
+{
+ hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ float x_scale = adaptor->x_scale;
+ float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
+
+ adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data HB_UNUSED)
+{
+ hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ float x_scale = adaptor->x_scale;
+ float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
+
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
+
+ adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *user_data HB_UNUSED)
+{
+ hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ float x_scale = adaptor->x_scale;
+ float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
+
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
+
+ adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
+ x_scale * control_x + slant * control_y, y_scale * control_y,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *user_data HB_UNUSED)
+{
+ hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ float x_scale = adaptor->x_scale;
+ float y_scale = adaptor->y_scale;
+ float slant = adaptor->slant;
+
+ st->current_x = st->current_x * x_scale + st->current_y * slant;
+ st->current_y = st->current_y * y_scale;
+
+ adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
+ x_scale * control1_x + slant * control1_y, y_scale * control1_y,
+ x_scale * control2_x + slant * control2_y, y_scale * control2_y,
+ x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+ hb_draw_state_t *st,
+ void *user_data HB_UNUSED)
{
+ hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+
+ adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
+}
+
+static const hb_draw_funcs_t _hb_draw_funcs_default = {
HB_OBJECT_HEADER_STATIC,
{
-#define HB_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
- },
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default,
+ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+ }
+};
+
+static void
+hb_font_get_glyph_shape_default (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs,
+ void *draw_data,
+ void *user_data HB_UNUSED)
+{
+ hb_font_get_glyph_shape_default_adaptor_t adaptor = {
+ draw_funcs,
+ draw_data,
+ font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
+ font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
+ font->parent->y_scale ? (font->slant - font->parent->slant) *
+ (float) font->x_scale / (float) font->parent->y_scale : 0.f
+ };
+
+ font->parent->get_glyph_shape (glyph,
+ const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
+ &adaptor);
+}
+
+DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
+{
+ HB_OBJECT_HEADER_STATIC,
+
+ nullptr,
+ nullptr,
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
@@ -527,16 +657,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,
@@ -548,7 +670,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.
*
@@ -615,10 +737,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);
}
@@ -631,9 +759,9 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
- * Attaches a user-data key/data pair to the specified font-functions structure.
+ * Attaches a user-data key/data pair to the specified font-functions structure.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -660,8 +788,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
* Since: 0.9.2
**/
void *
-hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
- hb_user_data_key_t *key)
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (ffuncs, key);
}
@@ -690,7 +818,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
*
* Tests whether a font-functions structure is immutable.
*
- * Return value: %true if @ffuncs is immutable, %false otherwise
+ * Return value: `true` if @ffuncs is immutable, `false` otherwise
*
* Since: 0.9.2
**/
@@ -701,6 +829,56 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
}
+static bool
+_hb_font_funcs_set_preamble (hb_font_funcs_t *ffuncs,
+ bool func_is_null,
+ void **user_data,
+ hb_destroy_func_t *destroy)
+{
+ if (hb_object_is_immutable (ffuncs))
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ return false;
+ }
+
+ if (func_is_null)
+ {
+ if (*destroy)
+ (*destroy) (*user_data);
+ *destroy = nullptr;
+ *user_data = nullptr;
+ }
+
+ return true;
+}
+
+static bool
+_hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs,
+ void *user_data,
+ hb_destroy_func_t destroy)
+{
+ 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;
+ }
+
+ return true;
+
+fail:
+ if (destroy)
+ (destroy) (user_data);
+ return false;
+}
+
#define HB_FONT_FUNC_IMPLEMENT(name) \
\
void \
@@ -709,25 +887,24 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
- if (hb_object_is_immutable (ffuncs)) \
- { \
- if (destroy) \
- destroy (user_data); \
- return; \
- } \
+ if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\
+ return; \
\
- 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 (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy)) \
+ return; \
\
- if (func) { \
+ if (func) \
ffuncs->get.f.name = func; \
- ffuncs->user_data.name = user_data; \
- ffuncs->destroy.name = destroy; \
- } else { \
+ 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 = user_data; \
+ if (ffuncs->destroy) \
+ ffuncs->destroy->name = destroy; \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -756,7 +933,7 @@ hb_font_t::has_func (unsigned int i)
* Fetches the extents for a specified font, for horizontal
* text segments.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 1.1.3
**/
@@ -775,7 +952,7 @@ hb_font_get_h_extents (hb_font_t *font,
* Fetches the extents for a specified font, for vertical
* text segments.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 1.1.3
**/
@@ -799,7 +976,7 @@ hb_font_get_v_extents (hb_font_t *font,
* If @variation_selector is 0, calls hb_font_get_nominal_glyph();
* otherwise calls hb_font_get_variation_glyph().
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -821,13 +998,13 @@ hb_font_get_glyph (hb_font_t *font,
* @glyph: (out): The glyph ID retrieved
*
* Fetches the nominal glyph ID for a Unicode code point in the
- * specified font.
+ * specified font.
*
* This version of the function should not be used to fetch glyph IDs
* for code points modified by variation selectors. For variation-selector
* support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 1.2.3
**/
@@ -879,7 +1056,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
* by the specified variation-selector code point, in the specified
* font.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 1.2.3
**/
@@ -940,7 +1117,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
* @advance_stride: The stride between successive advances
*
* Fetches the advances for a sequence of glyph IDs in the specified
- * font, for horizontal text segments.
+ * font, for horizontal text segments.
*
* Since: 1.8.6
**/
@@ -964,7 +1141,7 @@ hb_font_get_glyph_h_advances (hb_font_t* font,
* @advance_stride: (out): The stride between successive advances
*
* Fetches the advances for a sequence of glyph IDs in the specified
- * font, for vertical text segments.
+ * font, for vertical text segments.
*
* Since: 1.8.6
**/
@@ -989,7 +1166,7 @@ hb_font_get_glyph_v_advances (hb_font_t* font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for horizontal text segments.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1012,7 +1189,7 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for vertical text segments.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1085,7 +1262,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
* Fetches the #hb_glyph_extents_t data for a glyph ID
* in the specified font.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1108,7 +1285,7 @@ hb_font_get_glyph_extents (hb_font_t *font,
* Fetches the (x,y) coordinates of a specified contour-point index
* in the specified glyph, within the specified font.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1131,7 +1308,7 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
*
* Fetches the glyph-name string for a glyph ID in the specified @font.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1155,7 +1332,7 @@ hb_font_get_glyph_name (hb_font_t *font,
*
* <note>Note: @len == -1 means the name string is null-terminated.</note>
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1168,6 +1345,26 @@ hb_font_get_glyph_from_name (hb_font_t *font,
return font->get_glyph_from_name (name, len, glyph);
}
+/**
+ * hb_font_get_glyph_shape:
+ * @font: #hb_font_t to work upon
+ * @glyph: : The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Fetches the glyph shape that corresponds to a glyph in the specified @font.
+ * The shape is returned by way of calls to the callbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_font_get_glyph_shape (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+ font->get_glyph_shape (glyph, dfuncs, draw_data);
+}
/* A bit higher-level, and with fallback */
@@ -1190,7 +1387,7 @@ hb_font_get_extents_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_font_extents_t *extents)
{
- return font->get_extents_for_direction (direction, extents);
+ font->get_extents_for_direction (direction, extents);
}
/**
* hb_font_get_glyph_advance_for_direction:
@@ -1215,7 +1412,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_position_t *x,
hb_position_t *y)
{
- return font->get_glyph_advance_for_direction (glyph, direction, x, y);
+ font->get_glyph_advance_for_direction (glyph, direction, x, y);
}
/**
* hb_font_get_glyph_advances_for_direction:
@@ -1278,7 +1475,7 @@ hb_font_get_glyph_origin_for_direction (hb_font_t *font,
* @font: #hb_font_t to work upon
* @glyph: The glyph ID to query
* @direction: The direction of the text segment
- * @x: (inout): Input = The original X coordinate
+ * @x: (inout): Input = The original X coordinate
* Output = The X coordinate plus the X-coordinate of the origin
* @y: (inout): Input = The original Y coordinate
* Output = The Y coordinate plus the Y-coordinate of the origin
@@ -1306,7 +1503,7 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
* @font: #hb_font_t to work upon
* @glyph: The glyph ID to query
* @direction: The direction of the text segment
- * @x: (inout): Input = The original X coordinate
+ * @x: (inout): Input = The original X coordinate
* Output = The X coordinate minus the X-coordinate of the origin
* @y: (inout): Input = The original Y coordinate
* Output = The Y coordinate minus the Y-coordinate of the origin
@@ -1370,7 +1567,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1399,7 +1596,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1450,7 +1647,7 @@ hb_font_glyph_to_string (hb_font_t *font,
*
* <note>Note: @len == -1 means the string is null-terminated.</note>
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1472,11 +1669,18 @@ 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),
1000, /* x_scale */
1000, /* y_scale */
+ 0., /* slant */
+ 0., /* slant_xy; */
+ 1.f, /* x_multf */
+ 1.f, /* y_multf */
1<<16, /* x_mult */
1<<16, /* y_mult */
@@ -1501,6 +1705,7 @@ _hb_font_create (hb_face_t *face)
if (unlikely (!face))
face = hb_face_get_empty ();
+
if (!(font = hb_object_create<hb_font_t> ()))
return hb_font_get_empty ();
@@ -1509,18 +1714,26 @@ _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.
*
+ * <note>Note: If @face's index value (as passed to hb_face_create()
+ * has non-zero top 16-bits, those bits minus one are passed to
+ * hb_font_set_var_named_instance(), effectively loading a named-instance
+ * of a variable font, instead of the default-instance. This allows
+ * specifying which named-instance to load by default when creating the
+ * face.</note>
+ *
* Return value: (transfer full): The new font object
*
* Since: 0.9.2
@@ -1535,6 +1748,11 @@ hb_font_create (hb_face_t *face)
hb_ot_font_set_funcs (font);
#endif
+#ifndef HB_NO_VAR
+ if (face && face->index >> 16)
+ hb_font_set_var_named_instance (font, (face->index >> 16) - 1);
+#endif
+
return font;
}
@@ -1550,6 +1768,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
}
/**
@@ -1578,7 +1798,7 @@ hb_font_create_sub_font (hb_font_t *parent)
font->x_scale = parent->x_scale;
font->y_scale = parent->y_scale;
- font->mults_changed ();
+ font->slant = parent->slant;
font->x_ppem = parent->x_ppem;
font->y_ppem = parent->y_ppem;
font->ptem = parent->ptem;
@@ -1590,8 +1810,8 @@ hb_font_create_sub_font (hb_font_t *parent)
float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
if (likely (coords && design_coords))
{
- memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
- memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
+ hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
+ hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
_hb_font_adopt_var_coords (font, coords, design_coords, num_coords);
}
else
@@ -1601,6 +1821,8 @@ hb_font_create_sub_font (hb_font_t *parent)
}
}
+ font->mults_changed ();
+
return font;
}
@@ -1668,14 +1890,14 @@ hb_font_destroy (hb_font_t *font)
/**
* hb_font_set_user_data: (skip)
* @font: #hb_font_t to work upon
- * @key: The user-data key
+ * @key: The user-data key
* @data: A pointer to the user data
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
- * Attaches a user-data key/data pair to the specified font object.
+ * Attaches a user-data key/data pair to the specified font object.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1686,6 +1908,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);
}
@@ -1702,7 +1927,7 @@ hb_font_set_user_data (hb_font_t *font,
* Since: 0.9.2
**/
void *
-hb_font_get_user_data (hb_font_t *font,
+hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (font, key);
@@ -1734,7 +1959,7 @@ hb_font_make_immutable (hb_font_t *font)
*
* Tests whether a font object is immutable.
*
- * Return value: %true if @font is immutable, %false otherwise
+ * Return value: `true` if @font is immutable, `false` otherwise
*
* Since: 0.9.2
**/
@@ -1745,6 +1970,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
@@ -1760,6 +2024,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 ();
@@ -1802,6 +2071,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 ();
@@ -1856,6 +2130,8 @@ hb_font_set_funcs (hb_font_t *font,
return;
}
+ font->serial++;
+
if (font->destroy)
font->destroy (font->user_data);
@@ -1875,7 +2151,7 @@ hb_font_set_funcs (hb_font_t *font,
* @font_data: (destroy destroy) (scope notified): Data to attach to @font
* @destroy: (nullable): The function to call when @font_data is not needed anymore
*
- * Replaces the user data attached to a font, updating the font's
+ * Replaces the user data attached to a font, updating the font's
* @destroy callback.
*
* Since: 0.9.2
@@ -1893,6 +2169,8 @@ hb_font_set_funcs_data (hb_font_t *font,
return;
}
+ font->serial++;
+
if (font->destroy)
font->destroy (font->user_data);
@@ -1919,6 +2197,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 ();
@@ -1949,7 +2232,7 @@ hb_font_get_scale (hb_font_t *font,
* @x_ppem: Horizontal ppem value to assign
* @y_ppem: Vertical ppem value to assign
*
- * Sets the horizontal and vertical pixels-per-em (ppem) of a font.
+ * Sets the horizontal and vertical pixels-per-em (ppem) of a font.
*
* Since: 0.9.2
**/
@@ -1961,6 +2244,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;
}
@@ -1971,7 +2259,7 @@ hb_font_set_ppem (hb_font_t *font,
* @x_ppem: (out): Horizontal ppem value
* @y_ppem: (out): Vertical ppem value
*
- * Fetches the horizontal and vertical points-per-em (ppem) of a font.
+ * Fetches the horizontal and vertical points-per-em (ppem) of a font.
*
* Since: 0.9.2
**/
@@ -2003,6 +2291,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;
}
@@ -2015,7 +2308,7 @@ hb_font_set_ptem (hb_font_t *font,
*
* Return value: Point size. A value of zero means "not set."
*
- * Since: 0.9.2
+ * Since: 1.6.0
**/
float
hb_font_get_ptem (hb_font_t *font)
@@ -2023,6 +2316,58 @@ hb_font_get_ptem (hb_font_t *font)
return font->ptem;
}
+/**
+ * hb_font_set_synthetic_slant:
+ * @font: #hb_font_t to work upon
+ * @slant: synthetic slant value.
+ *
+ * Sets the "synthetic slant" of a font. By default is zero.
+ * Synthetic slant is the graphical skew applied to the font
+ * at rendering time.
+ *
+ * HarfBuzz needs to know this value to adjust shaping results,
+ * metrics, and style values to match the slanted rendering.
+ *
+ * <note>Note: The glyph shape fetched via the
+ * hb_font_get_glyph_shape() is slanted to reflect this value
+ * as well.</note>
+ *
+ * <note>Note: The slant value is a ratio. For example, a
+ * 20% slant would be represented as a 0.2 value.</note>
+ *
+ * Since: 3.3.0
+ **/
+HB_EXTERN void
+hb_font_set_synthetic_slant (hb_font_t *font, float slant)
+{
+ if (hb_object_is_immutable (font))
+ return;
+
+ if (font->slant == slant)
+ return;
+
+ font->serial++;
+
+ font->slant = slant;
+ font->mults_changed ();
+}
+
+/**
+ * hb_font_get_synthetic_slant:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the "synthetic slant" of a font.
+ *
+ * Return value: Synthetic slant. By default is zero.
+ *
+ * Since: 3.3.0
+ **/
+HB_EXTERN float
+hb_font_get_synthetic_slant (hb_font_t *font)
+{
+ return font->slant;
+}
+
#ifndef HB_NO_VAR
/*
* Variations
@@ -2036,6 +2381,10 @@ hb_font_get_ptem (hb_font_t *font)
*
* Applies a list of font-variation settings to a font.
*
+ * Note that this overrides all existing variations set on @font.
+ * Axes not included in @variations will be effectively set to their
+ * default values.
+ *
* Since: 1.4.2
*/
void
@@ -2046,6 +2395,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);
@@ -2066,6 +2417,10 @@ hb_font_set_variations (hb_font_t *font,
return;
}
+ /* Initialize design coords to default from fvar. */
+ for (unsigned int i = 0; i < coords_length; i++)
+ design_coords[i] = axes[i].get_default ();
+
for (unsigned int i = 0; i < variations_length; i++)
{
const auto tag = variations[i].tag;
@@ -2091,6 +2446,10 @@ hb_font_set_variations (hb_font_t *font,
* Applies a list of variation coordinates (in design-space units)
* to a font.
*
+ * Note that this overrides all existing variations set on @font.
+ * Axes not included in @coords will be effectively set to their
+ * default values.
+ *
* Since: 1.4.2
*/
void
@@ -2101,6 +2460,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;
@@ -2112,7 +2473,7 @@ hb_font_set_var_coords_design (hb_font_t *font,
}
if (coords_length)
- memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
+ hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -2134,6 +2495,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;
@@ -2154,6 +2517,10 @@ hb_font_set_var_named_instance (hb_font_t *font,
* Applies a list of variation coordinates (in normalized units)
* to a font.
*
+ * Note that this overrides all existing variations set on @font.
+ * Axes not included in @coords will be effectively set to their
+ * default values.
+ *
* <note>Note: Coordinates should be normalized to 2.14.</note>
*
* Since: 1.4.2
@@ -2166,6 +2533,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;
@@ -2180,8 +2549,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
if (coords_length)
{
- memcpy (copy, coords, coords_length * sizeof (coords[0]));
- memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
+ hb_memcpy (copy, coords, coords_length * sizeof (coords[0]));
+ hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
}
/* Best effort design coords simulation */
@@ -2196,14 +2565,19 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
/**
* hb_font_get_var_coords_normalized:
* @font: #hb_font_t to work upon
- * @length: Number of coordinates retrieved
+ * @length: (out): Number of coordinates retrieved
*
* Fetches the list of normalized variation coordinates currently
* set on a font.
*
+ * Note that this returned array may only contain values for some
+ * (or none) of the axes; omitted axes effectively have zero values.
+ *
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
+ * Return value: coordinates array
+ *
* Since: 1.4.2
*/
const int *
@@ -2216,18 +2590,24 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
return font->coords;
}
-#ifdef HB_EXPERIMENTAL_API
/**
* hb_font_get_var_coords_design:
* @font: #hb_font_t to work upon
- * @length: (out): number of coordinates
+ * @length: (out): Number of coordinates retrieved
+ *
+ * Fetches the list of variation coordinates (in design-space units) currently
+ * set on a font.
+ *
+ * Note that this returned array may only contain values for some
+ * (or none) of the axes; omitted axes effectively have their default
+ * values.
*
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
* Return value: coordinates array
*
- * Since: EXPERIMENTAL
+ * Since: 3.3.0
*/
const float *
hb_font_get_var_coords_design (hb_font_t *font,
@@ -2239,7 +2619,6 @@ hb_font_get_var_coords_design (hb_font_t *font,
return font->design_coords;
}
#endif
-#endif
#ifndef HB_DISABLE_DEPRECATED
/*
@@ -2361,12 +2740,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/src/hb-font.h b/src/hb-font.h
index 15dc12652..e2c3df4a5 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -86,8 +86,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
HB_EXTERN void *
-hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
- hb_user_data_key_t *key);
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key);
HB_EXTERN void
@@ -198,7 +198,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
* This method should retrieve the nominal glyph ID for a specified Unicode code
* point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -221,7 +221,7 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
* followed by a specified Variation Selector code point. Glyph IDs must be
* returned in a #hb_codepoint_t output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -362,7 +362,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
* origin for a glyph. Each coordinate must be returned in an #hb_position_t
* output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -434,7 +434,7 @@ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
* This method should retrieve the extents for a specified glyph. Extents must be
* returned in an #hb_glyph_extents output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -458,7 +458,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
* specified contour point in a glyph. Each coordinate must be returned as
* an #hb_position_t output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
@@ -481,7 +481,7 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
* This method should retrieve the glyph name that corresponds to a
* glyph ID. The name should be returned in a string output parameter.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
@@ -503,7 +503,7 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
* This method should retrieve the glyph ID that corresponds to a glyph-name
* string.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
@@ -511,6 +511,25 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
hb_codepoint_t *glyph,
void *user_data);
+/**
+ * hb_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data);
+
/* func setters */
@@ -770,6 +789,22 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t.
+ *
+ * Since: 4.0.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_shape_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
/* func dispatch */
HB_EXTERN hb_bool_t
@@ -850,6 +885,11 @@ hb_font_get_glyph_from_name (hb_font_t *font,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data);
+
/* high-level funcs, with fallback */
@@ -953,7 +993,7 @@ hb_font_set_user_data (hb_font_t *font,
HB_EXTERN void *
-hb_font_get_user_data (hb_font_t *font,
+hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key);
HB_EXTERN void
@@ -962,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);
@@ -1024,6 +1070,12 @@ HB_EXTERN float
hb_font_get_ptem (hb_font_t *font);
HB_EXTERN void
+hb_font_set_synthetic_slant (hb_font_t *font, float slant);
+
+HB_EXTERN float
+hb_font_get_synthetic_slant (hb_font_t *font);
+
+HB_EXTERN void
hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length);
@@ -1033,11 +1085,9 @@ hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length);
-#ifdef HB_EXPERIMENTAL_API
HB_EXTERN const float *
hb_font_get_var_coords_design (hb_font_t *font,
unsigned int *length);
-#endif
HB_EXTERN void
hb_font_set_var_coords_normalized (hb_font_t *font,
@@ -1052,11 +1102,6 @@ HB_EXTERN void
hb_font_set_var_named_instance (hb_font_t *font,
unsigned instance_index);
-#ifdef HB_EXPERIMENTAL_API
-HB_EXTERN hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
- const hb_draw_funcs_t *funcs, void *user_data);
-#endif
HB_END_DECLS
diff --git a/src/hb-font.hh b/src/hb-font.hh
index 1b7f445e8..6942d99c7 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -57,6 +57,7 @@
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_shape) \
/* ^--- Add new callbacks here */
struct hb_font_funcs_t
@@ -67,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 {
@@ -103,12 +104,18 @@ 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;
int32_t x_scale;
int32_t y_scale;
+ float slant;
+ float slant_xy;
+ float x_multf;
+ float y_multf;
int64_t x_mult;
int64_t y_mult;
@@ -134,10 +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); }
+ 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)); }
@@ -197,17 +206,17 @@ struct hb_font_t
hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
+ hb_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));
+ hb_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)
@@ -223,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,
@@ -235,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,
@@ -245,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,
@@ -272,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,
@@ -285,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,
@@ -294,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,
@@ -303,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,
@@ -314,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
}
@@ -326,18 +335,18 @@ 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
}
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
+ hb_memset (extents, 0, sizeof (*extents));
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,
@@ -347,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,
@@ -357,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 */
@@ -368,7 +377,16 @@ 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,
+ hb_draw_funcs_t *draw_funcs, void *draw_data)
+ {
+ klass->get.f.glyph_shape (this, user_data,
+ glyph,
+ draw_funcs, draw_data,
+ !klass->user_data ? nullptr : klass->user_data->glyph_shape);
}
@@ -430,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;
@@ -614,17 +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 (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/src/hb-ft.cc b/src/hb-ft.cc
index 97a2c82e6..3892dedc1 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -33,12 +33,16 @@
#include "hb-ft.h"
+#include "hb-draw.hh"
#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
+#include FT_OUTLINE_H
#include FT_TRUETYPE_TABLES_H
@@ -76,16 +80,19 @@
*/
+using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
+
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. */
+ bool transform; /* Whether to apply FT_Face's transform. */
- mutable int cached_x_scale;
- mutable hb_advance_cache_t advance_cache;
+ mutable hb_mutex_t lock; /* Protects members below. */
+ FT_Face ft_face;
+ mutable unsigned cached_serial;
+ mutable hb_ft_advance_cache_t advance_cache;
};
static hb_ft_font_t *
@@ -101,7 +108,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;
@@ -128,6 +135,85 @@ _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)
+{
+ hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+ float x_mult = 1.f, y_mult = 1.f;
+
+ if (font->x_scale < 0) x_mult = -x_mult;
+ if (font->y_scale < 0) y_mult = -y_mult;
+
+ if (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
+ ) && ft_face->num_fixed_sizes)
+ {
+#ifdef HAVE_FT_GET_TRANSFORM
+ /* Bitmap font, eg. bitmap color emoji. */
+ /* TODO Pick largest size? */
+ int x_scale = ft_face->available_sizes[0].x_ppem;
+ int y_scale = ft_face->available_sizes[0].y_ppem;
+ FT_Set_Char_Size (ft_face,
+ x_scale, y_scale,
+ 0, 0);
+
+ /* This contains the sign that was previously in x_mult/y_mult. */
+ x_mult = (float) font->x_scale / x_scale;
+ y_mult = (float) font->y_scale / y_scale;
+#endif
+ }
+ else
+ { /* Shrug */ }
+
+
+ if (x_mult != 1.f || y_mult != 1.f)
+ {
+ FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
+ 0, (int) roundf (y_mult * (1<<16))};
+ FT_Set_Transform (ft_face, &matrix, nullptr);
+ ft_font->transform = true;
+ }
+
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
+ unsigned int num_coords;
+ const float *coords = hb_font_get_var_coords_design (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] * 65536.f;
+ FT_Set_Var_Design_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
@@ -179,13 +265,13 @@ 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
* font object.
*
- * Return value: (nullable): the FT_Face found or %NULL
+ * Return value: (nullable): the FT_Face found or `NULL`
*
* Since: 0.9.2
**/
@@ -201,13 +287,13 @@ 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
* you call hb_ft_font_unlock_face().
*
- * Return value: (nullable): the FT_Face associated with @font or %NULL
+ * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
* Since: 2.6.5
**/
FT_Face
@@ -224,7 +310,7 @@ hb_ft_font_lock_face (hb_font_t *font)
}
/**
- * hb_ft_font_unlock_face:
+ * hb_ft_font_unlock_face: (skip)
* @font: #hb_font_t to work upon
*
* Releases an FT_Face previously obtained with hb_ft_font_lock_face().
@@ -244,7 +330,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,
@@ -256,14 +342,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;
}
@@ -333,12 +434,18 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
int load_flags = ft_font->load_flags;
- int mult = font->x_scale < 0 ? -1 : +1;
-
- if (font->x_scale != ft_font->cached_x_scale)
+ float x_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+ if (ft_font->transform)
{
- ft_font->advance_cache.clear ();
- ft_font->cached_x_scale = font->x_scale;
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ }
+ else
+#endif
+ {
+ x_mult = font->x_scale < 0 ? -1 : +1;
}
for (unsigned int i = 0; i < count; i++)
@@ -355,12 +462,13 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
ft_font->advance_cache.set (glyph, v);
}
- *first_advance = (v * mult + (1<<9)) >> 10;
+ *first_advance = (int) (v * x_mult + (1<<9)) >> 10;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
+#ifndef HB_NO_VERTICAL
static hb_position_t
hb_ft_get_glyph_v_advance (hb_font_t *font,
void *font_data,
@@ -370,18 +478,33 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Fixed v;
+ float y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
+#endif
+ {
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
- if (font->y_scale < 0)
- v = -v;
+ v = (int) (y_mult * v);
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
+
return (-v + (1<<9)) >> 10;
}
+#endif
+#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_ft_get_glyph_v_origin (hb_font_t *font,
void *font_data,
@@ -393,6 +516,21 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
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;
+ float x_mult, y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
+#endif
+ {
+ x_mult = font->x_scale < 0 ? -1 : +1;
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -402,13 +540,12 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
*x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX;
*y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
- if (font->x_scale < 0)
- *x = -*x;
- if (font->y_scale < 0)
- *y = -*y;
+ *x = (hb_position_t) (x_mult * *x);
+ *y = (hb_position_t) (y_mult * *y);
return true;
}
+#endif
#ifndef HB_NO_OT_SHAPE_FALLBACK
static hb_position_t
@@ -419,6 +556,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;
@@ -439,24 +577,30 @@ hb_ft_get_glyph_extents (hb_font_t *font,
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
-
- if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
- return false;
-
- extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
- extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
- extents->width = ft_face->glyph->metrics.width;
- extents->height = -ft_face->glyph->metrics.height;
- if (font->x_scale < 0)
+ float x_mult, y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+ if (ft_font->transform)
{
- extents->x_bearing = -extents->x_bearing;
- extents->width = -extents->width;
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
}
- if (font->y_scale < 0)
+ else
+#endif
{
- extents->y_bearing = -extents->y_bearing;
- extents->height = -extents->height;
+ x_mult = font->x_scale < 0 ? -1 : +1;
+ y_mult = font->y_scale < 0 ? -1 : +1;
}
+
+ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+ return false;
+
+ extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX);
+ extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY);
+ extents->width = (hb_position_t) (x_mult * ft_face->glyph->metrics.width);
+ extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height);
+
return true;
}
@@ -549,18 +693,121 @@ 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);
- if (font->y_scale < 0)
+ float y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+ if (ft_font->transform)
+ {
+ FT_Matrix matrix;
+ FT_Get_Transform (ft_face, &matrix, nullptr);
+ y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+ }
+ else
+#endif
+ {
+ y_mult = font->y_scale < 0 ? -1 : +1;
+ }
+
+ if (ft_face->units_per_EM != 0)
+ {
+ 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);
+ }
+ else
{
- metrics->ascender = -metrics->ascender;
- metrics->descender = -metrics->descender;
- metrics->line_gap = -metrics->line_gap;
+ /* Bitmap-only font, eg. color bitmap font. */
+ metrics->ascender = ft_face->size->metrics.ascender;
+ metrics->descender = ft_face->size->metrics.descender;
+ metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
}
+
+ metrics->ascender = (hb_position_t) (y_mult * metrics->ascender);
+ metrics->descender = (hb_position_t) (y_mult * metrics->descender);
+ metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap);
+
return true;
}
+#ifndef HB_NO_DRAW
+
+static int
+_hb_ft_move_to (const FT_Vector *to,
+ void *arg)
+{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+ drawing->move_to (to->x, to->y);
+ return FT_Err_Ok;
+}
+
+static int
+_hb_ft_line_to (const FT_Vector *to,
+ void *arg)
+{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+ drawing->line_to (to->x, to->y);
+ return FT_Err_Ok;
+}
+
+static int
+_hb_ft_conic_to (const FT_Vector *control,
+ const FT_Vector *to,
+ void *arg)
+{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+ drawing->quadratic_to (control->x, control->y,
+ to->x, to->y);
+ return FT_Err_Ok;
+}
+
+static int
+_hb_ft_cubic_to (const FT_Vector *control1,
+ const FT_Vector *control2,
+ const FT_Vector *to,
+ void *arg)
+{
+ hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+ drawing->cubic_to (control1->x, control1->y,
+ control2->x, control2->y,
+ to->x, to->y);
+ return FT_Err_Ok;
+}
+
+static void
+hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data HB_UNUSED)
+{
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
+
+ if (unlikely (FT_Load_Glyph (ft_face, glyph,
+ FT_LOAD_NO_BITMAP | ft_font->load_flags)))
+ return;
+
+ if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ return;
+
+ const FT_Outline_Funcs outline_funcs = {
+ _hb_ft_move_to,
+ _hb_ft_line_to,
+ _hb_ft_conic_to,
+ _hb_ft_cubic_to,
+ 0, /* shift */
+ 0, /* delta */
+ };
+
+ hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
+
+ FT_Outline_Decompose (&ft_face->glyph->outline,
+ &outline_funcs,
+ &draw_session);
+}
+#endif
+
+
static inline void free_static_ft_funcs ();
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
@@ -569,15 +816,20 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
- hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
- //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
+
+ hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+ //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
#ifndef HB_NO_OT_SHAPE_FALLBACK
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
#endif
@@ -587,6 +839,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
+#ifndef HB_NO_DRAW
+ hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr);
+#endif
+
hb_font_funcs_make_immutable (funcs);
hb_atexit (free_static_ft_funcs);
@@ -723,8 +979,9 @@ hb_ft_face_create_referenced (FT_Face ft_face)
}
static void
-hb_ft_face_finalize (FT_Face ft_face)
+hb_ft_face_finalize (void *arg)
{
+ FT_Face ft_face = (FT_Face) arg;
hb_face_destroy ((hb_face_t *) ft_face->generic.data);
}
@@ -756,7 +1013,7 @@ hb_ft_face_create_cached (FT_Face ft_face)
ft_face->generic.finalizer (ft_face);
ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
- ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+ ft_face->generic.finalizer = hb_ft_face_finalize;
}
return hb_face_reference ((hb_face_t *) ft_face->generic.data);
@@ -869,6 +1126,34 @@ hb_ft_font_changed (hb_font_t *font)
#endif
}
#endif
+
+ ft_font->advance_cache.clear ();
+ ft_font->cached_serial = font->serial;
+}
+
+/**
+ * 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);
}
/**
@@ -937,8 +1222,9 @@ get_ft_library ()
}
static void
-_release_blob (FT_Face ft_face)
+_release_blob (void *arg)
{
+ FT_Face ft_face = (FT_Face) arg;
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
}
@@ -989,41 +1275,14 @@ 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
ft_face->generic.data = blob;
- ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+ ft_face->generic.finalizer = _release_blob;
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
+
+ _hb_ft_hb_font_changed (font, ft_face);
}
diff --git a/src/hb-ft.h b/src/hb-ft.h
index bf07115ab..6a8a7abe8 100644
--- a/src/hb-ft.h
+++ b/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/src/hb-glib.cc b/src/hb-glib.cc
index 8ddc7ebad..1da81696e 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -129,32 +129,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_compose (a, b, ab);
+#else
+ return false;
#endif
-
- /* We don't ifdef-out the fallback code such that compiler always
- * sees it and makes sure it's compilable. */
-
- gchar utf8[12];
- gchar *normalized;
- int len;
- hb_bool_t ret;
-
- len = g_unichar_to_utf8 (a, utf8);
- len += g_unichar_to_utf8 (b, utf8 + len);
- normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
- len = g_utf8_strlen (normalized, -1);
- if (unlikely (!len))
- return false;
-
- if (len == 1) {
- *ab = g_utf8_get_char (normalized);
- ret = true;
- } else {
- ret = false;
- }
-
- g_free (normalized);
- return ret;
}
static hb_bool_t
@@ -166,55 +143,9 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_decompose (ab, a, b);
+#else
+ return false;
#endif
-
- /* We don't ifdef-out the fallback code such that compiler always
- * sees it and makes sure it's compilable. */
-
- gchar utf8[6];
- gchar *normalized;
- int len;
- hb_bool_t ret;
-
- len = g_unichar_to_utf8 (ab, utf8);
- normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
- len = g_utf8_strlen (normalized, -1);
- if (unlikely (!len))
- return false;
-
- if (len == 1) {
- *a = g_utf8_get_char (normalized);
- *b = 0;
- ret = *a != ab;
- } else if (len == 2) {
- *a = g_utf8_get_char (normalized);
- *b = g_utf8_get_char (g_utf8_next_char (normalized));
- /* Here's the ugly part: if ab decomposes to a single character and
- * that character decomposes again, we have to detect that and undo
- * the second part :-(. */
- gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
- hb_codepoint_t c = g_utf8_get_char (recomposed);
- if (c != ab && c != *a) {
- *a = c;
- *b = 0;
- }
- g_free (recomposed);
- ret = true;
- } else {
- /* If decomposed to more than two characters, take the last one,
- * and recompose the rest to get the first component. */
- gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
- gchar *recomposed;
- *b = g_utf8_get_char (end);
- recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
- /* We expect that recomposed has exactly one character now. */
- *a = g_utf8_get_char (recomposed);
- g_free (recomposed);
- ret = true;
- }
-
- g_free (normalized);
- return ret;
}
diff --git a/src/hb-gobject-enums.h.tmpl b/src/hb-gobject-enums.h.tmpl
index a8467868b..6dd98f7fe 100644
--- a/src/hb-gobject-enums.h.tmpl
+++ b/src/hb-gobject-enums.h.tmpl
@@ -43,7 +43,7 @@ HB_BEGIN_DECLS
/*** BEGIN value-header ***/
HB_EXTERN GType
-@enum_name@_get_type () G_GNUC_CONST;
+@enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 540b11f91..ef13f1e96 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -90,6 +90,7 @@ hb_gobject_##name##_get_type () \
HB_DEFINE_OBJECT_TYPE (buffer)
HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (draw_funcs)
HB_DEFINE_OBJECT_TYPE (face)
HB_DEFINE_OBJECT_TYPE (font)
HB_DEFINE_OBJECT_TYPE (font_funcs)
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
index 63467f80d..3914a2431 100644
--- a/src/hb-gobject-structs.h
+++ b/src/hb-gobject-structs.h
@@ -49,6 +49,10 @@ hb_gobject_buffer_get_type (void);
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
HB_EXTERN GType
+hb_gobject_draw_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ())
+
+HB_EXTERN GType
hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 209207f1e..9e068f8d8 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -158,7 +158,7 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
}
/**
- * hb_graphite2_face_get_gr_face:
+ * hb_graphite2_face_get_gr_face: (skip)
* @face: @hb_face_t to query
*
* Fetches the Graphite2 gr_face corresponding to the specified
@@ -195,10 +195,10 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
#ifndef HB_DISABLE_DEPRECATED
/**
- * hb_graphite2_font_get_gr_font:
+ * hb_graphite2_font_get_gr_font: (skip)
* @font: An #hb_font_t
*
- * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ * Always returns `NULL`. Use hb_graphite2_face_get_gr_face() instead.
*
* Return value: (nullable): Graphite2 font associated with @font.
*
@@ -223,7 +223,7 @@ struct hb_graphite2_cluster_t {
unsigned int base_glyph;
unsigned int num_glyphs;
unsigned int cluster;
- unsigned int advance;
+ int advance;
};
hb_bool_t
@@ -318,7 +318,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
#undef ALLOCATE_ARRAY
- memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
+ hb_memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
@@ -439,7 +439,8 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
if (feats) gr_featureval_destroy (feats);
gr_seg_destroy (seg);
- buffer->unsafe_to_break_all ();
+ buffer->clear_glyph_flags ();
+ buffer->unsafe_to_break ();
return true;
}
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index 87b8ed880..b57f37b13 100644
--- a/src/hb-iter.hh
+++ b/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,23 +70,20 @@ 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(); }
- iter_t begin () const { return *thiz(); }
- iter_t end () const { return thiz()->__end__ (); }
+ iter_t _begin () const { return *thiz(); }
+ iter_t begin () const { return _begin (); }
+ iter_t _end () const { return thiz()->__end__ (); }
+ iter_t end () const { return _end (); }
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 (hb_is_reference (T))>
- hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
+ hb_enable_if (std::is_reference<T>::value)>
+ hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); }
item_t operator * () const { return thiz()->__item__ (); }
item_t operator * () { return thiz()->__item__ (); }
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
@@ -128,7 +120,9 @@ struct hb_iter_t
#define HB_ITER_USING(Name) \
using item_t = typename Name::item_t; \
+ using Name::_begin; \
using Name::begin; \
+ using Name::_end; \
using Name::end; \
using Name::get_item_size; \
using Name::is_iterator; \
@@ -263,6 +257,8 @@ struct hb_is_iterator_of
};
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+#define hb_is_sorted_iterator_of(Iter, Item) (hb_is_iterator_of<Iter, Item>::value && Iter::is_sorted_iterator)
+#define hb_is_sorted_iterator(Iter) hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
/* hb_is_iterable() */
@@ -289,7 +285,7 @@ struct hb_is_source_of
{
private:
template <typename Iter2 = Iter,
- hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
+ hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<const Item>))>
static hb_true_type impl (hb_priority<2>);
template <typename Iter2 = Iter>
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
@@ -385,7 +381,7 @@ struct hb_map_iter_t :
void __forward__ (unsigned n) { it += n; }
void __prev__ () { --it; }
void __rewind__ (unsigned n) { it -= n; }
- hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
+ hb_map_iter_t __end__ () const { return hb_map_iter_t (it._end (), f); }
bool operator != (const hb_map_iter_t& o) const
{ return it != o.it; }
@@ -448,7 +444,7 @@ struct hb_filter_iter_t :
bool __more__ () const { return bool (it); }
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
- hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
+ hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); }
bool operator != (const hb_filter_iter_t& o) const
{ return it != o.it; }
@@ -561,7 +557,7 @@ struct hb_zip_iter_t :
void __forward__ (unsigned n) { a += n; b += n; }
void __prev__ () { --a; --b; }
void __rewind__ (unsigned n) { a -= n; b -= n; }
- hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
+ hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a._end (), b._end ()); }
/* Note, we should stop if ANY of the iters reaches end. As such two compare
* unequal if both items are unequal, NOT if either is unequal. */
bool operator != (const hb_zip_iter_t& o) const
@@ -581,6 +577,91 @@ struct
}
HB_FUNCOBJ (hb_zip);
+/* hb_concat() */
+
+template <typename A, typename B>
+struct hb_concat_iter_t :
+ hb_iter_t<hb_concat_iter_t<A, B>, typename A::item_t>
+{
+ hb_concat_iter_t () {}
+ hb_concat_iter_t (A& a, B& b) : a (a), b (b) {}
+ hb_concat_iter_t (const A& a, const B& b) : a (a), b (b) {}
+
+
+ typedef typename A::item_t __item_t__;
+ static constexpr bool is_random_access_iterator =
+ A::is_random_access_iterator &&
+ B::is_random_access_iterator;
+ static constexpr bool is_sorted_iterator = false;
+
+ __item_t__ __item__ () const
+ {
+ if (!a)
+ return *b;
+ return *a;
+ }
+
+ __item_t__ __item_at__ (unsigned i) const
+ {
+ unsigned a_len = a.len ();
+ if (i < a_len)
+ return a[i];
+ return b[i - a_len];
+ }
+
+ bool __more__ () const { return bool (a) || bool (b); }
+
+ unsigned __len__ () const { return a.len () + b.len (); }
+
+ void __next__ ()
+ {
+ if (a)
+ ++a;
+ else
+ ++b;
+ }
+
+ void __forward__ (unsigned n)
+ {
+ if (!n) return;
+ if (!is_random_access_iterator) {
+ while (n-- && *this) {
+ (*this)++;
+ }
+ return;
+ }
+
+ unsigned a_len = a.len ();
+ if (n > a_len) {
+ n -= a_len;
+ a.__forward__ (a_len);
+ b.__forward__ (n);
+ } else {
+ a.__forward__ (n);
+ }
+ }
+
+ hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); }
+ bool operator != (const hb_concat_iter_t& o) const
+ {
+ return a != o.a
+ || b != o.b;
+ }
+
+ private:
+ A a;
+ B b;
+};
+struct
+{ HB_PARTIALIZE(2);
+ template <typename A, typename B,
+ hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
+ hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>>
+ operator () (A&& a, B&& b) const
+ { return hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
+}
+HB_FUNCOBJ (hb_concat);
+
/* hb_apply() */
template <typename Appl>
diff --git a/src/hb-kern.hh b/src/hb-kern.hh
index 3f952fe7f..9ea945cae 100644
--- a/src/hb-kern.hh
+++ b/src/hb-kern.hh
@@ -49,6 +49,10 @@ struct hb_kern_machine_t
hb_mask_t kern_mask,
bool scale = true) const
{
+ if (!buffer->message (font, "start kern"))
+ return;
+
+ buffer->unsafe_to_concat ();
OT::hb_ot_apply_context_t c (1, font, buffer);
c.set_lookup_mask (kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
@@ -67,7 +71,8 @@ struct hb_kern_machine_t
}
skippy_iter.reset (idx, 1);
- if (!skippy_iter.next ())
+ unsigned unsafe_to;
+ if (!skippy_iter.next (&unsafe_to))
{
idx++;
continue;
@@ -125,6 +130,8 @@ struct hb_kern_machine_t
skip:
idx = skippy_iter.idx;
}
+
+ (void) buffer->message (font, "end kern");
}
const Driver &driver;
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 010c2570d..b555739cf 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -136,6 +136,13 @@ static inline Type& StructAfter(TObject &X)
/*
* Lazy loaders.
+ *
+ * The lazy-loaders are thread-safe pointer-like objects that create their
+ * instead on-demand. They also support access to a "data" object that is
+ * necessary for creating their instance. The data object, if specified,
+ * is accessed via pointer math, located at a location before the position
+ * of the loader itself. This avoids having to store a pointer to data
+ * for every lazy-loader. Multiple lazy-loaders can access the same data.
*/
template <typename Data, unsigned int WheresData>
@@ -176,12 +183,12 @@ 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_acquire ()); init (); }
void free_instance ()
{
retry:
- Stored *p = instance.get ();
+ Stored *p = instance.get_acquire ();
if (unlikely (p && !cmpexch (p, nullptr)))
goto retry;
do_destroy (p);
@@ -194,7 +201,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
const Returned * operator -> () const { return get (); }
- const Returned & operator * () const { return *get (); }
+ template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))>
+ const U & operator * () const { return *get (); }
explicit operator bool () const
{ return get_stored () != Funcs::get_null (); }
template <typename C> operator const C * () const { return get (); }
@@ -202,7 +210,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
Stored * get_stored () const
{
retry:
- Stored *p = this->instance.get ();
+ Stored *p = this->instance.get_acquire ();
if (unlikely (!p))
{
if (unlikely (this->is_inert ()))
@@ -227,7 +235,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
bool cmpexch (Stored *current, Stored *value) const
{
- /* This *must* be called when there are no other threads accessing. */
+ /* This function can only be safely called directly if no
+ * other thread is accessing. */
return this->instance.cmpexch (current, value);
}
@@ -244,23 +253,23 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
{
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
if (likely (p))
- p->init (data);
+ p = new (p) Stored (data);
return p;
}
static Stored *create ()
{
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
if (likely (p))
- p->init ();
+ p = new (p) Stored ();
return p;
}
static void destroy (Stored *p)
{
- p->fini ();
+ p->~Stored ();
hb_free (p);
}
-// private:
+ private:
/* Must only have one pointer. */
hb_atomic_ptr_t<Stored *> instance;
};
@@ -272,14 +281,19 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
hb_face_lazy_loader_t<T, WheresFace>,
hb_face_t, WheresFace> {};
-template <typename T, unsigned int WheresFace>
+template <typename T, unsigned int WheresFace, bool core=false>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
- hb_table_lazy_loader_t<T, WheresFace>,
+ hb_table_lazy_loader_t<T, WheresFace, core>,
hb_face_t, WheresFace,
hb_blob_t>
{
static hb_blob_t *create (hb_face_t *face)
- { return hb_sanitize_context_t ().reference_table<T> (face); }
+ {
+ auto c = hb_sanitize_context_t ();
+ if (core)
+ c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs
+ return c.reference_table<T> (face);
+ }
static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
static const hb_blob_t *get_null ()
diff --git a/src/hb-map.cc b/src/hb-map.cc
index 9f1ac4284..5c5f5de59 100644
--- a/src/hb-map.cc
+++ b/src/hb-map.cc
@@ -40,7 +40,7 @@
/**
- * hb_map_create: (Xconstructor)
+ * hb_map_create:
*
* Creates a new, initially empty map.
*
@@ -56,8 +56,6 @@ hb_map_create ()
if (!(map = hb_object_create<hb_map_t> ()))
return hb_map_get_empty ();
- map->init_shallow ();
-
return map;
}
@@ -107,8 +105,6 @@ hb_map_destroy (hb_map_t *map)
{
if (!hb_object_destroy (map)) return;
- map->fini_shallow ();
-
hb_free (map);
}
@@ -122,7 +118,7 @@ hb_map_destroy (hb_map_t *map)
*
* Attaches a user-data key/data pair to the specified map.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 1.7.7
**/
@@ -149,7 +145,7 @@ hb_map_set_user_data (hb_map_t *map,
* Since: 1.7.7
**/
void *
-hb_map_get_user_data (hb_map_t *map,
+hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (map, key);
@@ -162,7 +158,7 @@ hb_map_get_user_data (hb_map_t *map,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
*
* Since: 1.7.7
**/
@@ -172,6 +168,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:
@@ -232,7 +247,7 @@ hb_map_del (hb_map_t *map,
*
* Tests whether @key is an element of @map.
*
- * Return value: %true if @key is found in @map, %false otherwise
+ * Return value: `true` if @key is found in @map, `false` otherwise
*
* Since: 1.7.7
**/
@@ -264,7 +279,7 @@ hb_map_clear (hb_map_t *map)
*
* Tests whether @map is empty (contains no elements).
*
- * Return value: %true if @map is empty
+ * Return value: `true` if @map is empty
*
* Since: 1.7.7
**/
@@ -289,3 +304,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/src/hb-map.h b/src/hb-map.h
index 6a45a7bdd..3a067c5c7 100644
--- a/src/hb-map.h
+++ b/src/hb-map.h
@@ -74,7 +74,7 @@ hb_map_set_user_data (hb_map_t *map,
hb_bool_t replace);
HB_EXTERN void *
-hb_map_get_user_data (hb_map_t *map,
+hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key);
@@ -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/src/hb-map.hh b/src/hb-map.hh
index bb4a0eb5d..bfb1b3f76 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -34,20 +34,18 @@
* hb_hashmap_t
*/
+extern HB_INTERNAL const hb_codepoint_t minus_1;
+
template <typename K, typename V,
- K kINVALID = hb_is_pointer (K) ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1,
- V vINVALID = hb_is_pointer (V) ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1>
+ bool minus_one = false>
struct hb_hashmap_t
{
- static constexpr K INVALID_KEY = kINVALID;
- static constexpr V INVALID_VALUE = vINVALID;
-
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 (o.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) { reset (); resize (o.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 ()
@@ -59,31 +57,54 @@ struct hb_hashmap_t
hb_requires (hb_is_iterable (Iterable))>
hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
{
- hb_copy (o, *this);
+ auto iter = hb_iter (o);
+ if (iter.is_random_access_iterator)
+ resize (hb_len (iter));
+ hb_copy (iter, *this);
}
- static_assert (std::is_integral<K>::value || hb_is_pointer (K), "");
- static_assert (std::is_integral<V>::value || hb_is_pointer (V), "");
-
struct item_t
{
K key;
+ uint32_t hash : 30;
+ uint32_t is_used_ : 1;
+ uint32_t is_tombstone_ : 1;
V value;
- uint32_t hash;
- void clear () { key = kINVALID; value = vINVALID; hash = 0; }
+ item_t () : key (),
+ hash (0),
+ is_used_ (false), is_tombstone_ (false),
+ value () {}
+
+ 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;
+ };
- bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); }
- bool operator == (const item_t &o) { return *this == o.key; }
- bool is_unused () const { return key == kINVALID; }
- bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
- bool is_real () const { return key != kINVALID && value != vINVALID; }
+ bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
+ bool operator == (const item_t &o) const { return *this == o.key; }
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;
- bool successful; /* Allocations successful */
- unsigned int population; /* Not including tombstones. */
+ unsigned int successful : 1; /* Allocations successful */
+ unsigned int population : 31; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
@@ -93,35 +114,37 @@ struct hb_hashmap_t
{
if (unlikely (!a.successful || !b.successful))
return;
- hb_swap (a.population, b.population);
+ unsigned tmp = a.population;
+ a.population = b.population;
+ b.population = tmp;
+ //hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
hb_swap (a.items, b.items);
}
- void init_shallow ()
+ void init ()
{
+ hb_object_init (this);
+
successful = true;
population = occupancy = 0;
mask = 0;
prime = 0;
items = nullptr;
}
- void init ()
- {
- hb_object_init (this);
- init_shallow ();
- }
- void fini_shallow ()
- {
- hb_free (items);
- items = nullptr;
- population = occupancy = 0;
- }
void fini ()
{
hb_object_fini (this);
- fini_shallow ();
+
+ if (likely (items)) {
+ unsigned size = mask + 1;
+ for (unsigned i = 0; i < size; i++)
+ items[i].~item_t ();
+ hb_free (items);
+ items = nullptr;
+ }
+ population = occupancy = 0;
}
void reset ()
@@ -132,11 +155,13 @@ 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);
+ if (new_population != 0 && (new_population + new_population / 2) < mask) return true;
+
+ unsigned int power = hb_bit_storage (hb_max ((unsigned) 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))
@@ -145,9 +170,9 @@ struct hb_hashmap_t
return false;
}
for (auto &_ : hb_iter (new_items, new_size))
- _.clear ();
+ new (&_) item_t ();
- unsigned int old_size = mask + 1;
+ unsigned int old_size = size ();
item_t *old_items = items;
/* Switch to new, empty, array. */
@@ -157,50 +182,102 @@ struct hb_hashmap_t
items = new_items;
/* Insert back old items. */
- if (old_items)
- for (unsigned int i = 0; i < old_size; i++)
- if (old_items[i].is_real ())
- set_with_hash (old_items[i].key,
- old_items[i].hash,
- std::move (old_items[i].value));
+ for (unsigned int i = 0; i < old_size; i++)
+ {
+ if (old_items[i].is_real ())
+ {
+ set_with_hash (std::move (old_items[i].key),
+ old_items[i].hash,
+ std::move (old_items[i].value));
+ }
+ old_items[i].~item_t ();
+ }
hb_free (old_items);
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 KK, typename VV>
+ bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false)
+ {
+ if (unlikely (!successful)) return false;
+ if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
+ item_t &item = item_for_hash (key, hash);
- V get (K key) const
+ if (is_delete && !(item == key))
+ return true; /* Trying to delete non-existent key. */
+
+ if (item.is_used ())
+ {
+ occupancy--;
+ if (!item.is_tombstone ())
+ population--;
+ }
+
+ item.key = std::forward<KK> (key);
+ item.value = std::forward<VV> (value);
+ item.hash = hash;
+ item.set_used (true);
+ item.set_tombstone (is_delete);
+
+ occupancy++;
+ if (!is_delete)
+ population++;
+
+ return true;
+ }
+
+ template <typename VV>
+ bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
+ template <typename VV>
+ bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); }
+
+ const V& get_with_hash (const K &key, uint32_t hash) const
{
- if (unlikely (!items)) return vINVALID;
- unsigned int i = bucket_for (key);
- return items[i].is_real () && items[i] == key ? items[i].value : vINVALID;
+ if (unlikely (!items)) return item_t::default_value ();
+ auto &item = item_for_hash (key, hash);
+ return item.is_real () && item == key ? item.value : item_t::default_value ();
+ }
+ const V& get (const K &key) const
+ {
+ if (unlikely (!items)) return item_t::default_value ();
+ return get_with_hash (key, hb_hash (key));
}
- void del (K key) { set (key, vINVALID); }
+ void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
/* Has interface. */
- static constexpr V SENTINEL = vINVALID;
- typedef V value_t;
- value_t operator [] (K k) const { return get (k); }
- bool has (K k, V *vp = nullptr) const
+ const V& operator [] (K k) const { return get (k); }
+ template <typename VV=V>
+ bool has (K key, VV **vp = nullptr) const
{
- V v = (*this)[k];
- if (vp) *vp = v;
- return v != SENTINEL;
+ if (unlikely (!items))
+ return false;
+ auto &item = item_for_hash (key, hb_hash (key));
+ if (item.is_real () && item == key)
+ {
+ if (vp) *vp = std::addressof (item.value);
+ return true;
+ }
+ else
+ return false;
}
/* Projection. */
V operator () (K k) const { return get (k); }
+ unsigned size () const { return mask ? mask + 1 : 0; }
+
void clear ()
{
if (unlikely (!successful)) return;
- if (items)
- for (auto &_ : hb_iter (items, mask + 1))
- _.clear ();
+ for (auto &_ : hb_iter (items, size ()))
+ {
+ /* Reconstruct items. */
+ _.~item_t ();
+ new (&_) item_t ();
+ }
population = occupancy = 0;
}
@@ -208,86 +285,94 @@ struct hb_hashmap_t
bool is_empty () const { return population == 0; }
explicit operator bool () const { return !is_empty (); }
+ uint32_t hash () const
+ {
+ return
+ + iter_items ()
+ | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u)
+ ;
+ }
+
+ bool is_equal (const hb_hashmap_t &other) const
+ {
+ if (population != other.population) return false;
+
+ for (auto pair : iter ())
+ if (other.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; }
/*
* Iterator
*/
- auto iter () const HB_AUTO_RETURN
+
+ auto iter_items () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
+ + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
+ )
+ auto iter_ref () const HB_AUTO_RETURN
+ (
+ + iter_items ()
+ | hb_map (&item_t::get_pair_ref)
+ )
+ auto iter () const HB_AUTO_RETURN
+ (
+ + iter_items ()
| hb_map (&item_t::get_pair)
)
- auto keys () const HB_AUTO_RETURN
+ auto keys_ref () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
+ + iter_items ()
| hb_map (&item_t::key)
+ )
+ auto keys () const HB_AUTO_RETURN
+ (
+ + keys_ref ()
| hb_map (hb_ridentity)
)
- auto values () const HB_AUTO_RETURN
+ auto values_ref () const HB_AUTO_RETURN
(
- + hb_array (items, mask ? mask + 1 : 0)
- | hb_filter (&item_t::is_real)
+ + iter_items ()
| hb_map (&item_t::value)
+ )
+ auto values () const HB_AUTO_RETURN
+ (
+ + values_ref ()
| hb_map (hb_ridentity)
)
/* Sink interface. */
hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
{ set (v.first, v.second); return *this; }
-
- protected:
-
- template <typename VV>
- bool set_with_hash (K key, uint32_t hash, VV&& value)
- {
- if (unlikely (!successful)) return false;
- if (unlikely (key == kINVALID)) return true;
- if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
- unsigned int i = bucket_for_hash (key, hash);
-
- if (value == vINVALID && items[i].key != key)
- return true; /* Trying to delete non-existent key. */
-
- if (!items[i].is_unused ())
- {
- occupancy--;
- if (!items[i].is_tombstone ())
- population--;
- }
-
- items[i].key = key;
- items[i].value = value;
- items[i].hash = hash;
-
- occupancy++;
- if (!items[i].is_tombstone ())
- population++;
-
- return true;
- }
-
- unsigned int bucket_for (K key) const
- {
- return bucket_for_hash (key, hb_hash (key));
- }
-
- unsigned int bucket_for_hash (K key, uint32_t hash) const
+ hb_hashmap_t& operator << (const hb_pair_t<K, V&&>& v)
+ { set (v.first, std::move (v.second)); return *this; }
+ hb_hashmap_t& operator << (const hb_pair_t<K&&, V>& v)
+ { set (std::move (v.first), v.second); return *this; }
+ hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
+ { set (std::move (v.first), std::move (v.second)); return *this; }
+
+ item_t& item_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;
+ return items[i];
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
tombstone = i;
i = (i + ++step) & mask;
}
- return tombstone == (unsigned) -1 ? i : tombstone;
+ return items[tombstone == (unsigned) -1 ? i : tombstone];
}
static unsigned int prime_for (unsigned int shift)
@@ -348,23 +433,55 @@ struct hb_hashmap_t
struct hb_map_t : hb_hashmap_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_MAP_VALUE_INVALID,
- HB_MAP_VALUE_INVALID>;
+ true>;
- hb_map_t () = default;
~hb_map_t () = default;
- hb_map_t (hb_map_t& o) = default;
- hb_map_t& operator= (const hb_map_t& other) = default;
- hb_map_t& operator= (hb_map_t&& other) = 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) {}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
hb_map_t (const Iterable &o) : hashmap (o) {}
};
+template <typename K, typename V>
+static inline
+hb_hashmap_t<K, V>* hb_hashmap_create ()
+{
+ using hashmap = hb_hashmap_t<K, V>;
+ hashmap* map;
+ if (!(map = hb_object_create<hashmap> ()))
+ return nullptr;
+
+ return map;
+}
+
+template <typename K, typename V>
+static inline
+void hb_hashmap_destroy (hb_hashmap_t<K, V>* map)
+{
+ if (!hb_object_destroy (map))
+ return;
+
+ hb_free (map);
+}
+
+namespace hb {
+
+template <typename K, typename V>
+struct vtable<hb_hashmap_t<K, V>>
+{
+ static constexpr auto destroy = hb_hashmap_destroy<K,V>;
+};
+
+}
+
+
#endif /* HB_MAP_HH */
diff --git a/src/hb-meta.hh b/src/hb-meta.hh
index 0ea5774a9..31aa7fa6f 100644
--- a/src/hb-meta.hh
+++ b/src/hb-meta.hh
@@ -29,6 +29,7 @@
#include "hb.hh"
+#include <memory>
#include <type_traits>
#include <utility>
@@ -85,30 +86,13 @@ template <> struct hb_priority<0> {};
template <typename T> struct hb_type_identity_t { typedef T type; };
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
-struct
-{
- template <typename T> constexpr T*
- operator () (T& arg) const
- {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
- /* https://en.cppreference.com/w/cpp/memory/addressof */
- return reinterpret_cast<T*> (
- &const_cast<char&> (
- reinterpret_cast<const volatile char&> (arg)));
-#pragma GCC diagnostic pop
- }
-}
-HB_FUNCOBJ (hb_addressof);
-
template <typename T> static inline T hb_declval ();
#define hb_declval(T) (hb_declval<T> ())
template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
-template <typename T> using hb_add_const = const T;
-#define hb_is_const(T) hb_match_const<T>::value
+
template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_true_type {};
@@ -119,26 +103,24 @@ template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lval
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
-#define hb_is_reference(T) hb_match_reference<T>::value
+
template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
-#define hb_is_pointer(T) hb_match_pointer<T>::value
-/* TODO Add feature-parity to std::decay. */
-template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
+template <typename T> using hb_decay = typename std::decay<T>::type;
#define hb_is_convertible(From,To) std::is_convertible<From, To>::value
template <typename From, typename To>
using hb_is_cr_convertible = hb_bool_constant<
hb_is_same (hb_decay<From>, hb_decay<To>) &&
- (!hb_is_const (From) || hb_is_const (To)) &&
- (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
+ (!std::is_const<From>::value || std::is_const<To>::value) &&
+ (!std::is_reference<To>::value || std::is_const<To>::value || std::is_reference<To>::value)
>;
#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
@@ -150,18 +132,20 @@ struct
template <typename T> constexpr auto
operator () (T *v) const HB_AUTO_RETURN (*v)
-}
-HB_FUNCOBJ (hb_deref);
-struct
-{
template <typename T> constexpr auto
- operator () (T&& v) const HB_AUTO_RETURN (std::forward<T> (v))
+ operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
template <typename T> constexpr auto
- operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
+ operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
}
-HB_FUNCOBJ (hb_ref);
+HB_FUNCOBJ (hb_deref);
template <typename T>
struct hb_reference_wrapper
@@ -176,7 +160,7 @@ struct hb_reference_wrapper
template <typename T>
struct hb_reference_wrapper<T&>
{
- hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
+ hb_reference_wrapper (T& v) : v (std::addressof (v)) {}
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
operator T& () const { return *v; }
@@ -215,6 +199,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 && !defined(__clang__)
+#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/src/hb-ms-feature-ranges.cc b/src/hb-ms-feature-ranges.cc
deleted file mode 100644
index 6d09b252d..000000000
--- a/src/hb-ms-feature-ranges.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright © 2011,2012,2013 Google, Inc.
- * Copyright © 2021 Khaled Hosny
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-ms-feature-ranges.hh"
-
-bool
-hb_ms_setup_features (const hb_feature_t *features,
- unsigned int num_features,
- hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */
- hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
-{
- feature_records.shrink(0);
- range_records.shrink(0);
-
- /* Sort features by start/end events. */
- hb_vector_t<hb_ms_feature_event_t> feature_events;
- for (unsigned int i = 0; i < num_features; i++)
- {
- hb_ms_active_feature_t feature;
- feature.fea.tag_le = hb_uint32_swap (features[i].tag);
- feature.fea.value = features[i].value;
- feature.order = i;
-
- hb_ms_feature_event_t *event;
-
- event = feature_events.push ();
- event->index = features[i].start;
- event->start = true;
- event->feature = feature;
-
- event = feature_events.push ();
- event->index = features[i].end;
- event->start = false;
- event->feature = feature;
- }
- feature_events.qsort ();
- /* Add a strategic final event. */
- {
- hb_ms_active_feature_t feature;
- feature.fea.tag_le = 0;
- feature.fea.value = 0;
- feature.order = num_features + 1;
-
- auto *event = feature_events.push ();
- event->index = 0; /* This value does magic. */
- event->start = false;
- event->feature = feature;
- }
-
- /* Scan events and save features for each range. */
- hb_vector_t<hb_ms_active_feature_t> active_features;
- unsigned int last_index = 0;
- for (unsigned int i = 0; i < feature_events.length; i++)
- {
- auto *event = &feature_events[i];
-
- if (event->index != last_index)
- {
- /* Save a snapshot of active features and the range. */
- auto *range = range_records.push ();
- auto offset = feature_records.length;
-
- active_features.qsort ();
- for (unsigned int j = 0; j < active_features.length; j++)
- {
- if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
- {
- feature_records.push (active_features[j].fea);
- }
- else
- {
- /* Overrides value for existing feature. */
- feature_records[feature_records.length - 1].value = active_features[j].fea.value;
- }
- }
-
- /* Will convert to pointer after all is ready, since feature_records.array
- * may move as we grow it. */
- range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
- range->features.num_features = feature_records.length - offset;
- range->index_first = last_index;
- range->index_last = event->index - 1;
-
- last_index = event->index;
- }
-
- if (event->start)
- {
- active_features.push (event->feature);
- }
- else
- {
- auto *feature = active_features.find (&event->feature);
- if (feature)
- active_features.remove (feature - active_features.arrayZ);
- }
- }
-
- if (!range_records.length) /* No active feature found. */
- num_features = 0;
-
- /* Fixup the pointers. */
- for (unsigned int i = 0; i < range_records.length; i++)
- {
- auto *range = &range_records[i];
- range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
- }
-
- return !!num_features;
-}
-
-void
-hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records,
- hb_vector_t<hb_ms_range_record_t> &range_records,
- unsigned int chars_offset,
- unsigned int chars_len,
- uint16_t *log_clusters,
- hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */
- hb_vector_t<uint32_t> &range_counts /* OUT */)
-{
- range_features.shrink (0);
- range_counts.shrink (0);
-
- auto *last_range = &range_records[0];
- for (unsigned int i = chars_offset; i < chars_len; i++)
- {
- auto *range = last_range;
- while (log_clusters[i] < range->index_first)
- range--;
- while (log_clusters[i] > range->index_last)
- range++;
- if (!range_features.length ||
- &range->features != range_features[range_features.length - 1])
- {
- auto **features = range_features.push ();
- auto *c = range_counts.push ();
- if (unlikely (!features || !c))
- {
- range_features.shrink (0);
- range_counts.shrink (0);
- break;
- }
- *features = &range->features;
- *c = 1;
- }
- else
- {
- range_counts[range_counts.length - 1]++;
- }
-
- last_range = range;
- }
-}
diff --git a/src/hb-ms-feature-ranges.hh b/src/hb-ms-feature-ranges.hh
index 401d1e1d9..46a20c91e 100644
--- a/src/hb-ms-feature-ranges.hh
+++ b/src/hb-ms-feature-ranges.hh
@@ -52,8 +52,8 @@ struct hb_ms_active_feature_t {
a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 :
0;
}
- bool operator== (const hb_ms_active_feature_t *f)
- { return cmp (this, f) == 0; }
+ bool operator== (const hb_ms_active_feature_t& f) const
+ { return cmp (this, &f) == 0; }
};
struct hb_ms_feature_event_t {
@@ -77,20 +77,153 @@ struct hb_ms_range_record_t {
unsigned int index_last; /* == end - 1 */
};
-HB_INTERNAL bool
+static inline bool
hb_ms_setup_features (const hb_feature_t *features,
unsigned int num_features,
hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */
- hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */);
+ hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
+{
+ feature_records.shrink(0);
+ range_records.shrink(0);
+ /* Sort features by start/end events. */
+ hb_vector_t<hb_ms_feature_event_t> feature_events;
+ for (unsigned int i = 0; i < num_features; i++)
+ {
+ hb_ms_active_feature_t feature;
+ feature.fea.tag_le = hb_uint32_swap (features[i].tag);
+ feature.fea.value = features[i].value;
+ feature.order = i;
+
+ hb_ms_feature_event_t *event;
+
+ event = feature_events.push ();
+ event->index = features[i].start;
+ event->start = true;
+ event->feature = feature;
+
+ event = feature_events.push ();
+ event->index = features[i].end;
+ event->start = false;
+ event->feature = feature;
+ }
+ feature_events.qsort ();
+ /* Add a strategic final event. */
+ {
+ hb_ms_active_feature_t feature;
+ feature.fea.tag_le = 0;
+ feature.fea.value = 0;
+ feature.order = num_features + 1;
+
+ auto *event = feature_events.push ();
+ event->index = 0; /* This value does magic. */
+ event->start = false;
+ event->feature = feature;
+ }
+
+ /* Scan events and save features for each range. */
+ hb_vector_t<hb_ms_active_feature_t> active_features;
+ unsigned int last_index = 0;
+ for (unsigned int i = 0; i < feature_events.length; i++)
+ {
+ auto *event = &feature_events[i];
+
+ if (event->index != last_index)
+ {
+ /* Save a snapshot of active features and the range. */
+ auto *range = range_records.push ();
+ auto offset = feature_records.length;
+
+ active_features.qsort ();
+ for (unsigned int j = 0; j < active_features.length; j++)
+ {
+ if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
+ {
+ feature_records.push (active_features[j].fea);
+ }
+ else
+ {
+ /* Overrides value for existing feature. */
+ feature_records[feature_records.length - 1].value = active_features[j].fea.value;
+ }
+ }
+
+ /* Will convert to pointer after all is ready, since feature_records.array
+ * may move as we grow it. */
+ range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
+ range->features.num_features = feature_records.length - offset;
+ range->index_first = last_index;
+ range->index_last = event->index - 1;
-HB_INTERNAL void
+ last_index = event->index;
+ }
+
+ if (event->start)
+ {
+ active_features.push (event->feature);
+ }
+ else
+ {
+ auto *feature = active_features.lsearch (event->feature);
+ if (feature)
+ active_features.remove_ordered (feature - active_features.arrayZ);
+ }
+ }
+
+ if (!range_records.length) /* No active feature found. */
+ num_features = 0;
+
+ /* Fixup the pointers. */
+ for (unsigned int i = 0; i < range_records.length; i++)
+ {
+ auto *range = &range_records[i];
+ range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
+ }
+
+ return !!num_features;
+}
+
+static inline void
hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records,
hb_vector_t<hb_ms_range_record_t> &range_records,
unsigned int chars_offset,
unsigned int chars_len,
uint16_t *log_clusters,
hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */
- hb_vector_t<uint32_t> &range_counts /* OUT */);
+ hb_vector_t<uint32_t> &range_counts /* OUT */)
+{
+ range_features.shrink (0);
+ range_counts.shrink (0);
+
+ auto *last_range = &range_records[0];
+ for (unsigned int i = chars_offset; i < chars_len; i++)
+ {
+ auto *range = last_range;
+ while (log_clusters[i] < range->index_first)
+ range--;
+ while (log_clusters[i] > range->index_last)
+ range++;
+ if (!range_features.length ||
+ &range->features != range_features[range_features.length - 1])
+ {
+ auto **features = range_features.push ();
+ auto *c = range_counts.push ();
+ if (unlikely (!features || !c))
+ {
+ range_features.shrink (0);
+ range_counts.shrink (0);
+ break;
+ }
+ *features = &range->features;
+ *c = 1;
+ }
+ else
+ {
+ range_counts[range_counts.length - 1]++;
+ }
+
+ last_range = range;
+ }
+}
#endif /* HB_MS_FEATURE_RANGES_HH */
diff --git a/src/hb-multimap.hh b/src/hb-multimap.hh
new file mode 100644
index 000000000..f0f95917a
--- /dev/null
+++ b/src/hb-multimap.hh
@@ -0,0 +1,92 @@
+/*
+ * 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_MULTIMAP_HH
+#define HB_MULTIMAP_HH
+
+#include "hb.hh"
+#include "hb-map.hh"
+#include "hb-vector.hh"
+
+
+/*
+ * hb_multimap_t
+ */
+
+struct hb_multimap_t
+{
+ void add (hb_codepoint_t k, hb_codepoint_t v)
+ {
+ hb_codepoint_t *i;
+ if (multiples_indices.has (k, &i))
+ {
+ multiples_values[*i].push (v);
+ return;
+ }
+
+ hb_codepoint_t *old_v;
+ if (singulars.has (k, &old_v))
+ {
+ hb_codepoint_t old = *old_v;
+ singulars.del (k);
+
+ multiples_indices.set (k, multiples_values.length);
+ auto *vec = multiples_values.push ();
+
+ vec->push (old);
+ vec->push (v);
+
+ return;
+ }
+
+ singulars.set (k, v);
+ }
+
+ hb_array_t<const hb_codepoint_t> get (hb_codepoint_t k) const
+ {
+ hb_codepoint_t *v;
+ if (singulars.has (k, &v))
+ return hb_array (v, 1);
+
+ hb_codepoint_t *i;
+ if (multiples_indices.has (k, &i))
+ return multiples_values[*i].as_array ();
+
+ return hb_array_t<hb_codepoint_t> ();
+ }
+
+ bool in_error () const
+ {
+ return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
+ }
+
+ protected:
+ hb_map_t singulars;
+ hb_map_t multiples_indices;
+ hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values;
+};
+
+
+
+#endif /* HB_MULTIMAP_HH */
diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh
index 6914b2245..053f9ddcc 100644
--- a/src/hb-mutex.hh
+++ b/src/hb-mutex.hh
@@ -108,10 +108,11 @@ struct hb_mutex_t
struct hb_lock_t
{
- hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); }
- ~hb_lock_t () { mutex.unlock (); }
+ hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); }
+ hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); }
+ ~hb_lock_t () { if (mutex) mutex->unlock (); }
private:
- hb_mutex_t &mutex;
+ hb_mutex_t *mutex;
};
diff --git a/src/hb-null.hh b/src/hb-null.hh
index db38a4dfd..0d7f4da79 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -37,7 +37,25 @@
/* Global nul-content Null pool. Enlarge as necessary. */
-#define HB_NULL_POOL_SIZE 384
+#define HB_NULL_POOL_SIZE 448
+
+template <typename T, typename>
+struct _hb_has_min_size : hb_false_type {};
+template <typename T>
+struct _hb_has_min_size<T, hb_void_t<decltype (T::min_size)>>
+ : hb_true_type {};
+template <typename T>
+using hb_has_min_size = _hb_has_min_size<T, void>;
+#define hb_has_min_size(T) hb_has_min_size<T>::value
+
+template <typename T, typename>
+struct _hb_has_null_size : hb_false_type {};
+template <typename T>
+struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>>
+ : hb_true_type {};
+template <typename T>
+using hb_has_null_size = _hb_has_null_size<T, void>;
+#define hb_has_null_size(T) hb_has_null_size<T>::value
/* 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 +126,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 () { \
@@ -117,8 +135,19 @@ struct NullHelper
}; \
namespace Namespace { \
static_assert (true, "") /* Require semicolon after. */
+#define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \
+ } /* Close namespace. */ \
+ extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \
+ template <typename Spec> \
+ struct Null<Namespace::Type<Spec>> { \
+ static Namespace::Type<Spec> const & get_null () { \
+ return *reinterpret_cast<const Namespace::Type<Spec> *> (_hb_Null_##Namespace##_##Type); \
+ } \
+ }; \
+ 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[sizeof (_hb_Null_##Namespace##_##Type)]
/* Specializations for arbitrary-content Null objects expressed as struct initializer. */
#define DECLARE_NULL_INSTANCE(Type) \
diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh
index 1a9dbba6d..ec68c3a72 100644
--- a/src/hb-number-parser.hh
+++ b/src/hb-number-parser.hh
@@ -31,7 +31,7 @@
#include "hb.hh"
-#line 35 "hb-number-parser.hh"
+#line 32 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
-#line 139 "hb-number-parser.hh"
+#line 132 "hb-number-parser.hh"
{
cs = double_parser_start;
}
-#line 144 "hb-number-parser.hh"
+#line 135 "hb-number-parser.hh"
{
int _slen;
int _trans;
@@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
-#line 202 "hb-number-parser.hh"
+#line 187 "hb-number-parser.hh"
}
_again:
diff --git a/src/hb-object.hh b/src/hb-object.hh
index 0e15cb12c..a23c25f7c 100644
--- a/src/hb-object.hh
+++ b/src/hb-object.hh
@@ -53,7 +53,7 @@ struct hb_lockable_set_t
item_t *replace_or_insert (T v, lock_t &l, bool replace)
{
l.lock ();
- item_t *item = items.find (v);
+ item_t *item = items.lsearch (v);
if (item) {
if (replace) {
item_t old = *item;
@@ -76,11 +76,11 @@ struct hb_lockable_set_t
void remove (T v, lock_t &l)
{
l.lock ();
- item_t *item = items.find (v);
+ item_t *item = items.lsearch (v);
if (item)
{
item_t old = *item;
- *item = items[items.length - 1];
+ *item = std::move (items.tail ());
items.pop ();
l.unlock ();
old.fini ();
@@ -93,7 +93,7 @@ struct hb_lockable_set_t
bool find (T v, item_t *i, lock_t &l)
{
l.lock ();
- item_t *item = items.find (v);
+ item_t *item = items.lsearch (v);
if (item)
*i = *item;
l.unlock ();
@@ -123,7 +123,7 @@ struct hb_lockable_set_t
l.lock ();
while (items.length)
{
- item_t old = items[items.length - 1];
+ item_t old = items.tail ();
items.pop ();
l.unlock ();
old.fini ();
@@ -144,14 +144,14 @@ struct hb_reference_count_t
{
mutable hb_atomic_int_t ref_count;
- void init (int v = 1) { ref_count.set_relaxed (v); }
- int get_relaxed () const { return ref_count.get_relaxed (); }
+ void init (int v = 1) { ref_count = v; }
+ int get_relaxed () const { return ref_count; }
int inc () const { return ref_count.inc (); }
int dec () const { return ref_count.dec (); }
- void fini () { ref_count.set_relaxed (-0x0000DEAD); }
+ void fini () { ref_count = -0x0000DEAD; }
- bool is_inert () const { return !ref_count.get_relaxed (); }
- bool is_valid () const { return ref_count.get_relaxed () > 0; }
+ bool is_inert () const { return !ref_count; }
+ bool is_valid () const { return ref_count > 0; }
};
@@ -214,23 +214,26 @@ static inline void hb_object_trace (const Type *obj, const char *function)
obj ? obj->header.ref_count.get_relaxed () : 0);
}
-template <typename Type>
-static inline Type *hb_object_create ()
+template <typename Type, typename ...Ts>
+static inline Type *hb_object_create (Ts... ds)
{
Type *obj = (Type *) hb_calloc (1, sizeof (Type));
if (unlikely (!obj))
return obj;
+ new (obj) Type (std::forward<Ts> (ds)...);
+
hb_object_init (obj);
hb_object_trace (obj, HB_FUNC);
+
return obj;
}
template <typename Type>
static inline void hb_object_init (Type *obj)
{
obj->header.ref_count.init ();
- obj->header.writable.set_relaxed (true);
+ obj->header.writable = true;
obj->header.user_data.init ();
}
template <typename Type>
@@ -241,12 +244,12 @@ static inline bool hb_object_is_valid (const Type *obj)
template <typename Type>
static inline bool hb_object_is_immutable (const Type *obj)
{
- return !obj->header.writable.get_relaxed ();
+ return !obj->header.writable;
}
template <typename Type>
static inline void hb_object_make_immutable (const Type *obj)
{
- obj->header.writable.set_relaxed (false);
+ obj->header.writable = false;
}
template <typename Type>
static inline Type *hb_object_reference (Type *obj)
@@ -269,18 +272,22 @@ static inline bool hb_object_destroy (Type *obj)
return false;
hb_object_fini (obj);
+
+ if (!std::is_trivially_destructible<Type>::value)
+ obj->~Type ();
+
return true;
}
template <typename Type>
static inline void hb_object_fini (Type *obj)
{
obj->header.ref_count.fini (); /* Do this before user_data */
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (user_data)
{
user_data->fini ();
hb_free (user_data);
- user_data = nullptr;
+ obj->header.user_data.set_relaxed (nullptr);
}
}
template <typename Type>
@@ -295,7 +302,7 @@ static inline bool hb_object_set_user_data (Type *obj,
assert (hb_object_is_valid (obj));
retry:
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data))
{
user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
@@ -320,7 +327,7 @@ static inline void *hb_object_get_user_data (Type *obj,
if (unlikely (!obj || obj->header.is_inert ()))
return nullptr;
assert (hb_object_is_valid (obj));
- hb_user_data_array_t *user_data = obj->header.user_data.get ();
+ hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (!user_data)
return nullptr;
return user_data->get (key);
diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh
index 6eee5827c..13570a46e 100644
--- a/src/hb-open-file.hh
+++ b/src/hb-open-file.hh
@@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable
{
if (table_count)
{
- + tables.sub_array (start_offset, table_count)
+ + tables.as_array ().sub_array (start_offset, table_count)
| hb_map (&TableRecord::tag)
| hb_sink (hb_array (table_tags, *table_count))
;
@@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable
return_trace (false);
if (likely (len))
- memcpy (start, blob->data, len);
+ hb_memcpy (start, blob->data, len);
/* 4-byte alignment. */
c->align (4);
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 7e524177f..290799127 100644
--- a/src/hb-open-type.hh
+++ b/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"
@@ -104,7 +105,7 @@ struct IntType
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
BEInt<Type, Size> v;
@@ -140,27 +141,27 @@ typedef HBINT32 FWORD32;
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
typedef HBUINT16 UFWORD;
-/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : HBINT16
+template <typename Type, unsigned fraction_bits>
+struct HBFixed : Type
{
- F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
- // 16384 means 1<<14
- float to_float () const { return ((int32_t) v) / 16384.f; }
- void set_float (float f) { v = roundf (f * 16384.f); }
+ static constexpr float shift = (float) (1 << fraction_bits);
+ static_assert (Type::static_size * 8 > fraction_bits, "");
+
+ HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
+ float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; }
+ void set_float (float f) { Type::v = roundf (f * shift); }
public:
- DEFINE_SIZE_STATIC (2);
+ DEFINE_SIZE_STATIC (Type::static_size);
};
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+using F2DOT14 = HBFixed<HBINT16, 14>;
+
+/* 16-bit signed fixed number with the low 12 bits of fraction (4.12). */
+using F4DOT12 = HBFixed<HBINT16, 12>;
+
/* 32-bit signed fixed-point number (16.16). */
-struct HBFixed : HBINT32
-{
- HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
- // 65536 means 1<<16
- float to_float () const { return ((int32_t) v) / 65536.f; }
- void set_float (float f) { v = roundf (f * 65536.f); }
- public:
- DEFINE_SIZE_STATIC (4);
-};
+using F16DOT16 = HBFixed<HBINT32, 16>;
/* Date represented in number of seconds since 12:00 midnight, January 1,
* 1904. The value is represented as a signed 64-bit integer. */
@@ -169,7 +170,7 @@ struct LONGDATETIME
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
HBINT32 major;
@@ -195,6 +196,10 @@ struct HBGlyphID16 : HBUINT16
{
HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
};
+struct HBGlyphID24 : HBUINT24
+{
+ HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
+};
/* Script/language-system/feature index */
struct Index : HBUINT16 {
@@ -207,6 +212,12 @@ typedef Index NameID;
struct VarIdx : HBUINT32 {
static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
+ static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, "");
+ static uint32_t add (uint32_t i, unsigned short v)
+ {
+ if (i == NO_VARIATION) return i;
+ return i + v;
+ }
VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
};
DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
@@ -299,6 +310,10 @@ struct _hb_has_null<Type, true>
template <typename Type, typename OffsetType, bool has_null=true>
struct OffsetTo : Offset<OffsetType, has_null>
{
+ // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
+ static_assert (has_null == false ||
+ (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
+
HB_DELETE_COPY_ASSIGN (OffsetTo);
OffsetTo () = default;
@@ -449,14 +464,16 @@ struct UnsizedArrayOf
{
unsigned int i = (unsigned int) i_;
const Type *p = &arrayZ[i];
- if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
+ if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
+ _hb_compiler_memory_r_barrier ();
return *p;
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
Type *p = &arrayZ[i];
- if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
+ if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
+ _hb_compiler_memory_r_barrier ();
return *p;
}
@@ -485,10 +502,10 @@ struct UnsizedArrayOf
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
{ as_array (len).qsort (start, end); }
- bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+ bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend (this, items_len))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@@ -496,8 +513,8 @@ struct UnsizedArrayOf
bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -518,7 +535,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);
@@ -549,14 +566,16 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
{
unsigned int i = (unsigned int) i_;
const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
- if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
+ if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
+ _hb_compiler_memory_r_barrier ();
return this+*p;
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
- if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
+ if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
+ _hb_compiler_memory_r_barrier ();
return this+*p;
}
@@ -607,12 +626,14 @@ struct ArrayOf
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= len)) return Null (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i];
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= len)) return Crap (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i];
}
@@ -634,14 +655,9 @@ struct ArrayOf
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ const Type *begin () const { return arrayZ; }
+ const Type *end () const { return arrayZ + len; }
template <typename T>
Type &lsearch (const T &x, Type &not_found = Crap (Type))
@@ -655,15 +671,15 @@ struct ArrayOf
unsigned int to_store = (unsigned int) -1) const
{ return as_array ().lfind (x, i, not_found, to_store); }
- void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
- { as_array ().qsort (start, end); }
+ void qsort ()
+ { as_array ().qsort (); }
- HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
- if (unlikely (!c->extend (this))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@@ -671,8 +687,8 @@ struct ArrayOf
HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -707,7 +723,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)...)))
@@ -728,6 +744,7 @@ struct ArrayOf
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
using PString = ArrayOf<HBUINT8, HBUINT8>;
@@ -737,26 +754,28 @@ template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUI
template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
/* Array of offsets relative to the beginning of the array itself. */
-template <typename Type>
-struct List16OfOffset16To : Array16OfOffset16To<Type>
+template <typename Type, typename OffsetType>
+struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
{
const Type& operator [] (int i_) const
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= this->len)) return Null (Type);
+ _hb_compiler_memory_r_barrier ();
return this+this->arrayZ[i];
}
const Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= this->len)) return Crap (Type);
+ _hb_compiler_memory_r_barrier ();
return this+this->arrayZ[i];
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
+ struct List16OfOffsetTo *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
unsigned int count = this->len;
for (unsigned int i = 0; i < count; i++)
@@ -768,10 +787,13 @@ struct List16OfOffset16To : Array16OfOffset16To<Type>
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
- return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
+ return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
}
};
+template <typename Type>
+using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
+
/* An array starting at second element. */
template <typename Type, typename LenType=HBUINT16>
struct HeadlessArrayOf
@@ -784,12 +806,14 @@ struct HeadlessArrayOf
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= lenP1 || !i)) return Null (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i-1];
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= lenP1 || !i)) return Crap (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i-1];
}
unsigned int get_size () const
@@ -808,21 +832,25 @@ struct HeadlessArrayOf
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+ /* Faster range-based for loop. */
+ const Type *begin () const { return arrayZ; }
+ const Type *end () const { return arrayZ + get_length (); }
+
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
- if (unlikely (!c->extend (this))) return_trace (false);
+ if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, Type))>
- bool serialize (hb_serialize_context_t *c, Iterator items)
+ HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- unsigned count = items.len ();
- if (unlikely (!serialize (c, count))) return_trace (false);
+ unsigned count = hb_len (items);
+ if (unlikely (!serialize (c, count, false))) return_trace (false);
/* TODO Umm. Just exhaust the iterator instead? Being extra
* cautious right now.. */
for (unsigned i = 0; i < count; i++, ++items)
@@ -835,7 +863,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)...)))
@@ -868,12 +896,14 @@ struct ArrayOfM1
{
unsigned int i = (unsigned int) i_;
if (unlikely (i > lenM1)) return Null (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i];
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
if (unlikely (i > lenM1)) return Crap (Type);
+ _hb_compiler_memory_r_barrier ();
return arrayZ[i];
}
unsigned int get_size () const
@@ -884,7 +914,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)...)))
@@ -922,14 +952,9 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ const Type *begin () const { return this->arrayZ; }
+ const Type *end () const { return this->arrayZ + this->len; }
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
{
@@ -960,6 +985,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
};
template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
/*
@@ -1052,12 +1078,14 @@ struct VarSizedBinSearchArrayOf
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= get_length ())) return Null (Type);
+ _hb_compiler_memory_r_barrier ();
return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
}
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= get_length ())) return Crap (Type);
+ _hb_compiler_memory_r_barrier ();
return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
}
unsigned int get_length () const
@@ -1070,7 +1098,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/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh
index 180c87cb8..f22824fc6 100644
--- a/src/hb-ot-cff-common.hh
+++ b/src/hb-ot-cff-common.hh
@@ -46,163 +46,45 @@ template<typename Type>
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
-inline unsigned int calcOffSize (unsigned int dataSize)
-{
- unsigned int size = 1;
- unsigned int offset = dataSize + 1;
- while (offset & ~0xFF)
- {
- size++;
- offset >>= 8;
- }
- /* format does not support size > 4; caller should handle it as an error */
- return size;
-}
-
struct code_pair_t
{
hb_codepoint_t code;
hb_codepoint_t glyph;
};
-typedef hb_vector_t<unsigned char> str_buff_t;
-struct str_buff_vec_t : hb_vector_t<str_buff_t>
-{
- void fini () { SUPER::fini_deep (); }
-
- unsigned int total_size () const
- {
- unsigned int size = 0;
- for (unsigned int i = 0; i < length; i++)
- size += (*this)[i].length;
- return size;
- }
-
- private:
- typedef hb_vector_t<str_buff_t> SUPER;
-};
+using str_buff_t = hb_vector_t<unsigned char>;
+using str_buff_vec_t = hb_vector_t<str_buff_t>;
/* CFF INDEX */
template <typename COUNT>
struct CFFIndex
{
- static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
- { return offSize * (count + 1); }
-
unsigned int offset_array_size () const
- { return calculate_offset_array_size (offSize, count); }
+ { return offSize * (count + 1); }
CFFIndex *copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
unsigned int size = get_size ();
- CFFIndex *out = c->allocate_size<CFFIndex> (size);
+ CFFIndex *out = c->allocate_size<CFFIndex> (size, false);
if (likely (out))
- memcpy (out, this, size);
+ hb_memcpy (out, this, size);
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);
- }
-
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const byte_str_array_t &byteArray)
+ const Iterable &iterable)
{
TRACE_SERIALIZE (this);
- if (byteArray.length == 0)
- {
- COUNT *dest = c->allocate_min<COUNT> ();
- if (unlikely (!dest)) return_trace (false);
- *dest = 0;
- }
- 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 ();
- }
- 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);
- }
- }
+ auto it = hb_iter (iterable);
+ serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len));
+ for (const auto &_ : +it)
+ hb_iter (_).copy (c);
return_trace (true);
}
- bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const str_buff_vec_t &buffArray)
- {
- byte_str_array_t byteArray;
- 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);
- bool result = this->serialize (c, offSize_, byteArray);
- byteArray.fini ();
- return result;
- }
-
- template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c,
- 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);
- }
- return_trace (true);
- }
-
- bool serialize (hb_serialize_context_t *c,
- const byte_str_array_t &byteArray)
- { return serialize (c, + hb_iter (byteArray)); }
-
- bool serialize (hb_serialize_context_t *c,
- const str_buff_vec_t &buffArray)
- {
- auto it =
- + hb_iter (buffArray)
- | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); })
- ;
- return serialize (c, it);
- }
-
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
@@ -211,13 +93,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), false)))
return_trace (false);
/* serialize indices */
@@ -225,16 +109,30 @@ struct CFFIndex
unsigned int i = 0;
for (unsigned _ : +it)
{
- CFFIndex<COUNT>::set_offset_at (i++, offset);
+ set_offset_at (i++, offset);
offset += _;
}
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ set_offset_at (i, offset);
return_trace (true);
}
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
+ static unsigned total_size (const Iterable &iterable)
+ {
+ auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len);
+ if (!it) return 0;
+
+ unsigned total = + it | hb_reduce (hb_add, 0);
+ unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+
+ return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
+ }
+
void set_offset_at (unsigned int index, unsigned int offset)
{
+ assert (index <= count);
HBUINT8 *p = offsets + offSize * index + offSize;
unsigned int size = offSize;
for (; size; size--)
@@ -245,85 +143,77 @@ struct CFFIndex
}
}
+ private:
unsigned int offset_at (unsigned int index) const
{
assert (index <= count);
- const HBUINT8 *p = offsets + offSize * index;
+
unsigned int size = offSize;
- unsigned int offset = 0;
- for (; size; size--)
- offset = (offset << 8) + *p++;
- return offset;
+ const HBUINT8 *p = offsets + size * index;
+ switch (size)
+ {
+ case 1: return * (HBUINT8 *) p;
+ case 2: return * (HBUINT16 *) p;
+ case 3: return * (HBUINT24 *) p;
+ case 4: return * (HBUINT32 *) p;
+ default: return 0;
+ }
}
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 ();
+ _hb_compiler_memory_r_barrier ();
+ 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_,
@@ -338,7 +228,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = dataArrayLen;
this->offSize = offSize_;
- if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
+ if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1), false)))
return_trace (false);
/* serialize indices */
@@ -346,10 +236,10 @@ struct CFFIndexOf : CFFIndex<COUNT>
unsigned int i = 0;
for (; i < dataArrayLen; i++)
{
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ this->set_offset_at (i, offset);
offset += dataSizeArray[i];
}
- CFFIndex<COUNT>::set_offset_at (i, offset);
+ this->set_offset_at (i, offset);
/* serialize data */
for (unsigned int i = 0; i < dataArrayLen; i++)
@@ -382,13 +272,12 @@ struct Dict : UnsizedByteStr
template <typename T, typename V>
static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp)
{
- // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
- if (/*unlikely*/ (!serialize_int<T, V> (c, intOp, value)))
+ if (unlikely ((!serialize_int<T, V> (c, intOp, value))))
return false;
TRACE_SERIALIZE (this);
/* serialize the opcode */
- HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
+ HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op), false);
if (unlikely (!p)) return_trace (false);
if (Is_OpCode_ESC (op))
{
@@ -473,9 +362,8 @@ struct FDSelect0 {
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this))))
return_trace (false);
- for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
- if (unlikely (!fds[i].sanitize (c)))
- return_trace (false);
+ if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
+ return_trace (false);
return_trace (true);
}
@@ -529,14 +417,20 @@ struct FDSelect3_4
return_trace (true);
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ static int _cmp_range (const void *_key, const void *_item)
{
- unsigned int i;
- for (i = 1; i < nRanges (); i++)
- if (glyph < ranges[i].first)
- break;
+ hb_codepoint_t glyph = * (hb_codepoint_t *) _key;
+ FDSelect3_4_Range<GID_TYPE, FD_TYPE> *range = (FDSelect3_4_Range<GID_TYPE, FD_TYPE> *) _item;
+
+ if (glyph < range[0].first) return -1;
+ if (glyph < range[1].first) return 0;
+ return +1;
+ }
- return (hb_codepoint_t) ranges[i - 1].fd;
+ hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ {
+ auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+ return range ? range->fd : ranges[nRanges () - 1].fd;
}
GID_TYPE &nRanges () { return ranges.len; }
@@ -559,9 +453,9 @@ struct FDSelect
{
TRACE_SERIALIZE (this);
unsigned int size = src.get_size (num_glyphs);
- FDSelect *dest = c->allocate_size<FDSelect> (size);
+ FDSelect *dest = c->allocate_size<FDSelect> (size, false);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc
index 3298fa35a..bd9fe5d6d 100644
--- a/src/hb-ot-cff1-table.cc
+++ b/src/hb-ot-cff1-table.cc
@@ -311,10 +311,8 @@ struct bounds_t
struct cff1_extents_param_t
{
- void init (const OT::cff1::accelerator_t *_cff)
+ cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
{
- path_open = false;
- cff = _cff;
bounds.init ();
}
@@ -322,7 +320,7 @@ struct cff1_extents_param_t
void end_path () { path_open = false; }
bool is_path_open () const { return path_open; }
- bool path_open;
+ bool path_open = false;
bounds_t bounds;
const OT::cff1::accelerator_t *cff;
@@ -395,12 +393,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
unsigned int fd = cff->fdSelect->get_fd (glyph);
- cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
- const byte_str_t str = (*cff->charStrings)[glyph];
- interp.env.init (str, *cff, fd);
- interp.env.set_in_seac (in_seac);
- cff1_extents_param_t param;
- param.init (cff);
+ const hb_ubytes_t str = (*cff->charStrings)[glyph];
+ cff1_cs_interp_env_t env (str, *cff, fd);
+ env.set_in_seac (in_seac);
+ cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env);
+ cff1_extents_param_t param (cff);
if (unlikely (!interp.interpret (param))) return false;
bounds = param.bounds;
return true;
@@ -442,13 +439,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
return true;
}
-#ifdef HB_EXPERIMENTAL_API
struct cff1_path_param_t
{
cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
- draw_helper_t &draw_helper_, point_t *delta_)
+ hb_draw_session_t &draw_session_, point_t *delta_)
{
- draw_helper = &draw_helper_;
+ draw_session = &draw_session_;
cff = cff_;
font = font_;
delta = delta_;
@@ -458,14 +454,14 @@ struct cff1_path_param_t
{
point_t point = p;
if (delta) point.move (*delta);
- draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+ draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
}
void line_to (const point_t &p)
{
point_t point = p;
if (delta) point.move (*delta);
- draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+ draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
}
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
@@ -477,15 +473,15 @@ struct cff1_path_param_t
point2.move (*delta);
point3.move (*delta);
}
- draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
- font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
- font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
+ draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
+ font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
+ font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
}
- void end_path () { draw_helper->end_path (); }
+ void end_path () { draw_session->close_path (); }
hb_font_t *font;
- draw_helper_t *draw_helper;
+ hb_draw_session_t *draw_session;
point_t *delta;
const OT::cff1::accelerator_t *cff;
@@ -513,7 +509,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int
};
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
- draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
+ hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
{
@@ -530,23 +526,23 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa
hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
if (unlikely (!(!env.in_seac && base && accent
- && _get_path (param.cff, param.font, base, *param.draw_helper, true)
- && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
+ && _get_path (param.cff, param.font, base, *param.draw_session, true)
+ && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
env.set_error ();
}
};
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
- draw_helper_t &draw_helper, bool in_seac, point_t *delta)
+ hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
{
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
unsigned int fd = cff->fdSelect->get_fd (glyph);
- cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp;
- const byte_str_t str = (*cff->charStrings)[glyph];
- interp.env.init (str, *cff, fd);
- interp.env.set_in_seac (in_seac);
- cff1_path_param_t param (cff, font, draw_helper, delta);
+ const hb_ubytes_t str = (*cff->charStrings)[glyph];
+ cff1_cs_interp_env_t env (str, *cff, fd);
+ env.set_in_seac (in_seac);
+ cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
+ cff1_path_param_t param (cff, font, draw_session, delta);
if (unlikely (!interp.interpret (param))) return false;
/* Let's end the path specially since it is called inside seac also */
@@ -555,31 +551,25 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
return true;
}
-bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
return true;
#endif
- return _get_path (this, font, glyph, draw_helper);
+ return _get_path (this, font, glyph, draw_session);
}
-#endif
struct get_seac_param_t
{
- void init (const OT::cff1::accelerator_t *_cff)
- {
- cff = _cff;
- base = 0;
- accent = 0;
- }
+ get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {}
bool has_seac () const { return base && accent; }
const OT::cff1::accelerator_t *cff;
- hb_codepoint_t base;
- hb_codepoint_t accent;
+ hb_codepoint_t base = 0;
+ hb_codepoint_t accent = 0;
};
struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
@@ -600,11 +590,10 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
unsigned int fd = fdSelect->get_fd (glyph);
- cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp;
- const byte_str_t str = (*charStrings)[glyph];
- interp.env.init (str, *this, fd);
- get_seac_param_t param;
- param.init (this);
+ const hb_ubytes_t str = (*charStrings)[glyph];
+ cff1_cs_interp_env_t env (str, *this, fd);
+ cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
+ get_seac_param_t param (this);
if (unlikely (!interp.interpret (param))) return false;
if (param.has_seac ())
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index 5dd183e3a..bb856c9dd 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -175,7 +175,7 @@ struct Encoding
unsigned int size = src.get_size ();
Encoding *dest = c->allocate_size<Encoding> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -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;
@@ -446,7 +471,7 @@ struct Charset
unsigned int size = src.get_size (num_glyphs);
Charset *dest = c->allocate_size<Charset> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -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)
@@ -582,7 +617,6 @@ struct CFF1StringIndex : CFF1Index
}
byte_str_array_t bytesArray;
- bytesArray.init ();
if (!bytesArray.resize (sidmap.get_population ()))
return_trace (false);
for (unsigned int i = 0; i < strings.count; i++)
@@ -593,7 +627,6 @@ struct CFF1StringIndex : CFF1Index
}
bool result = CFF1Index::serialize (c, bytesArray);
- bytesArray.fini ();
return_trace (result);
}
};
@@ -602,6 +635,8 @@ struct cff1_top_dict_interp_env_t : num_interp_env_t
{
cff1_top_dict_interp_env_t ()
: num_interp_env_t(), prev_offset(0), last_offset(0) {}
+ cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes)
+ : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {}
unsigned int prev_offset;
unsigned int last_offset;
@@ -776,7 +811,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
default:
- env.last_offset = env.str_ref.offset;
+ env.last_offset = env.str_ref.get_offset ();
top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval);
/* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty ()) return;
@@ -1024,11 +1059,10 @@ struct cff1
{ fini (); return; }
{ /* parse top dict */
- const byte_str_t topDictStr = (*topDictIndex)[0];
+ const hb_ubytes_t topDictStr = (*topDictIndex)[0];
if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
- cff1_top_dict_interpreter_t top_interp;
- top_interp.env.init (topDictStr);
- topDict.init ();
+ cff1_top_dict_interp_env_t env (topDictStr);
+ cff1_top_dict_interpreter_t top_interp (env);
if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
}
@@ -1098,20 +1132,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 +1161,10 @@ struct cff1
cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0];
- const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
+ const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
- priv_interp.env.init (privDictStr);
+ num_interp_env_t env (privDictStr);
+ dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
@@ -1144,8 +1179,8 @@ struct cff1
{
sc.end_processing ();
topDict.fini ();
- fontDicts.fini_deep ();
- privateDicts.fini_deep ();
+ fontDicts.fini ();
+ privateDicts.fini ();
hb_blob_destroy (blob);
blob = nullptr;
}
@@ -1194,6 +1229,19 @@ struct cff1
}
}
+ hb_map_t *create_glyph_to_sid_map () const
+ {
+ if (charset != &Null (Charset))
+ {
+ hb_map_t *mapping = hb_map_create ();
+ mapping->set (0, 0);
+ charset->collect_glyph_to_sid_map (mapping, num_glyphs);
+ return mapping;
+ }
+ else
+ return nullptr;
+ }
+
hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
{
if (charset != &Null (Charset))
@@ -1245,60 +1293,49 @@ struct cff1
}
protected:
- hb_blob_t *blob;
hb_sanitize_context_t sc;
public:
- const Encoding *encoding;
- const Charset *charset;
- const CFF1NameIndex *nameIndex;
- const CFF1TopDictIndex *topDictIndex;
- const CFF1StringIndex *stringIndex;
- const CFF1Subrs *globalSubrs;
- const CFF1CharStrings *charStrings;
- const CFF1FDArray *fdArray;
- const CFF1FDSelect *fdSelect;
- unsigned int fdCount;
+ hb_blob_t *blob = nullptr;
+ const Encoding *encoding = nullptr;
+ const Charset *charset = nullptr;
+ const CFF1NameIndex *nameIndex = nullptr;
+ const CFF1TopDictIndex *topDictIndex = nullptr;
+ const CFF1StringIndex *stringIndex = nullptr;
+ const CFF1Subrs *globalSubrs = nullptr;
+ const CFF1CharStrings *charStrings = nullptr;
+ const CFF1FDArray *fdArray = nullptr;
+ const CFF1FDSelect *fdSelect = nullptr;
+ unsigned int fdCount = 0;
cff1_top_dict_values_t topDict;
hb_vector_t<cff1_font_dict_values_t>
fontDicts;
hb_vector_t<PRIVDICTVAL> privateDicts;
- unsigned int num_glyphs;
+ unsigned int num_glyphs = 0;
};
struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
SUPER::init (face);
+ glyph_names.set_relaxed (nullptr);
+
if (!is_valid ()) return;
if (is_CID ()) return;
- /* fill glyph_names */
- for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
- {
- hb_codepoint_t sid = glyph_to_sid (gid);
- gname_t gname;
- gname.sid = sid;
- if (sid < cff1_std_strings_length)
- gname.name = cff1_std_strings (sid);
- else
- {
- byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length];
- gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length);
- }
- if (unlikely (!gname.name.arrayZ)) { fini (); return; }
- glyph_names.push (gname);
- }
- glyph_names.qsort ();
}
-
- void fini ()
+ ~accelerator_t ()
{
- glyph_names.fini ();
+ hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed ();
+ if (names)
+ {
+ names->fini ();
+ hb_free (names);
+ }
SUPER::fini ();
}
@@ -1306,9 +1343,9 @@ struct cff1
bool get_glyph_name (hb_codepoint_t glyph,
char *buf, unsigned int buf_len) const
{
- if (!buf) return true;
if (unlikely (!is_valid ())) return false;
if (is_CID()) return false;
+ if (unlikely (!buf_len)) return true;
hb_codepoint_t sid = glyph_to_sid (glyph);
const char *str;
size_t str_len;
@@ -1320,7 +1357,7 @@ struct cff1
}
else
{
- byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
+ hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
str = (const char *)ubyte_str.arrayZ;
str_len = ubyte_str.length;
}
@@ -1334,11 +1371,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_acquire ();
+ 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;
@@ -1348,9 +1427,7 @@ struct cff1
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
-#ifdef HB_EXPERIMENTAL_API
- HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+ HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
private:
struct gname_t
@@ -1362,7 +1439,7 @@ struct cff1
{
const gname_t *a = (const gname_t *)a_;
const gname_t *b = (const gname_t *)b_;
- int minlen = hb_min (a->name.length, b->name.length);
+ unsigned minlen = hb_min (a->name.length, b->name.length);
int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen);
if (ret) return ret;
return a->name.length - b->name.length;
@@ -1371,7 +1448,7 @@ struct cff1
int cmp (const gname_t &a) const { return cmp (&a, this); }
};
- hb_sorted_vector_t<gname_t> glyph_names;
+ mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names;
typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
};
@@ -1398,7 +1475,10 @@ struct cff1
DEFINE_SIZE_STATIC (4);
};
-struct cff1_accelerator_t : cff1::accelerator_t {};
+struct cff1_accelerator_t : cff1::accelerator_t {
+ cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF1_TABLE_HH */
diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc
index 879b7cdb2..50c76daf9 100644
--- a/src/hb-ot-cff2-table.cc
+++ b/src/hb-ot-cff2-table.cc
@@ -36,9 +36,8 @@ using namespace CFF;
struct cff2_extents_param_t
{
- void init ()
+ cff2_extents_param_t ()
{
- path_open = false;
min_x.set_int (INT_MAX);
min_y.set_int (INT_MAX);
max_x.set_int (INT_MIN);
@@ -57,22 +56,22 @@ struct cff2_extents_param_t
if (pt.y > max_y) max_y = pt.y;
}
- bool path_open;
+ bool path_open = false;
number_t min_x;
number_t min_y;
number_t max_x;
number_t max_y;
};
-struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
+struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t>
{
- static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
+ static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt)
{
param.end_path ();
env.moveto (pt);
}
- static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
+ static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1)
{
if (!param.is_path_open ())
{
@@ -83,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
param.update_bounds (env.get_pt ());
}
- static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+ static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
if (!param.is_path_open ())
{
@@ -98,7 +97,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
}
};
-struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
+struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {};
bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
hb_codepoint_t glyph,
@@ -112,11 +111,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
unsigned int fd = fdSelect->get_fd (glyph);
- cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
- const byte_str_t str = (*charStrings)[glyph];
- interp.env.init (str, *this, fd, font->coords, font->num_coords);
+ const hb_ubytes_t str = (*charStrings)[glyph];
+ cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+ cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env);
cff2_extents_param_t param;
- param.init ();
if (unlikely (!interp.interpret (param))) return false;
if (param.min_x >= param.max_x)
@@ -143,57 +141,56 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
return true;
}
-#ifdef HB_EXPERIMENTAL_API
struct cff2_path_param_t
{
- cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+ cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
- draw_helper = &draw_helper_;
+ draw_session = &draw_session_;
font = font_;
}
void move_to (const point_t &p)
- { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+ { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
void line_to (const point_t &p)
- { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+ { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
{
- draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
- font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
- font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
+ draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()),
+ font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()),
+ font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ()));
}
protected:
- draw_helper_t *draw_helper;
+ hb_draw_session_t *draw_session;
hb_font_t *font;
};
-struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
+struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t>
{
- static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
+ static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt)
{
param.move_to (pt);
env.moveto (pt);
}
- static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
+ static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1)
{
param.line_to (pt1);
env.moveto (pt1);
}
- static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+ static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
param.cubic_to (pt1, pt2, pt3);
env.moveto (pt3);
}
};
-struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
+struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {};
-bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
@@ -203,13 +200,12 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
unsigned int fd = fdSelect->get_fd (glyph);
- cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
- const byte_str_t str = (*charStrings)[glyph];
- interp.env.init (str, *this, fd, font->coords, font->num_coords);
- cff2_path_param_t param (font, draw_helper);
+ const hb_ubytes_t str = (*charStrings)[glyph];
+ cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+ cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env);
+ cff2_path_param_t param (font, draw_session);
if (unlikely (!interp.interpret (param))) return false;
return true;
}
-#endif
#endif
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index 829217fea..9081930bb 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -56,7 +56,7 @@ struct CFF2FDSelect
unsigned int size = src.get_size (num_glyphs);
CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, &src, size);
+ hb_memcpy (dest, &src, size);
return_trace (true);
}
@@ -124,7 +124,7 @@ struct CFF2VariationStore
unsigned int size_ = varStore->get_size ();
CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
if (unlikely (!dest)) return_trace (false);
- memcpy (dest, varStore, size_);
+ hb_memcpy (dest, varStore, size_);
return_trace (true);
}
@@ -247,12 +247,8 @@ typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values
struct cff2_priv_dict_interp_env_t : num_interp_env_t
{
- void init (const byte_str_t &str)
- {
- num_interp_env_t::init (str);
- ivs = 0;
- seen_vsindex = false;
- }
+ cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) :
+ num_interp_env_t (str) {}
void process_vsindex ()
{
@@ -267,8 +263,8 @@ struct cff2_priv_dict_interp_env_t : num_interp_env_t
void set_ivs (unsigned int ivs_) { ivs = ivs_; }
protected:
- unsigned int ivs;
- bool seen_vsindex;
+ unsigned int ivs = 0;
+ bool seen_vsindex = false;
};
struct cff2_private_dict_opset_t : dict_opset_t
@@ -397,7 +393,7 @@ struct cff2
template <typename PRIVOPSET, typename PRIVDICTVAL>
struct accelerator_templ_t
{
- void init (hb_face_t *face)
+ accelerator_templ_t (hb_face_t *face)
{
topDict.init ();
fontDicts.init ();
@@ -412,15 +408,15 @@ struct cff2
const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
if (cff2 == &Null (OT::cff2))
- { fini (); return; }
+ goto fail;
{ /* parse top dict */
- byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
- if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
- cff2_top_dict_interpreter_t top_interp;
- top_interp.env.init (topDictStr);
+ hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
+ if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
+ num_interp_env_t env (topDictStr);
+ cff2_top_dict_interpreter_t top_interp (env);
topDict.init ();
- if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
+ if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
@@ -434,82 +430,93 @@ struct cff2
(globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
(fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
(((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
- { fini (); return; }
+ goto fail;
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
- { fini (); return; }
+ goto fail;
fdCount = fdArray->count;
if (!privateDicts.resize (fdCount))
- { fini (); return; }
+ goto fail;
/* parse font dicts and gather private dicts */
for (unsigned int i = 0; i < fdCount; i++)
{
- const byte_str_t fontDictStr = (*fdArray)[i];
- if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
+ const hb_ubytes_t fontDictStr = (*fdArray)[i];
+ if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
cff2_font_dict_values_t *font;
- cff2_font_dict_interpreter_t font_interp;
- font_interp.env.init (fontDictStr);
+ num_interp_env_t env (fontDictStr);
+ cff2_font_dict_interpreter_t font_interp (env);
font = fontDicts.push ();
- if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; }
+ if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
font->init ();
- if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
+ if (unlikely (!font_interp.interpret (*font))) goto fail;
- const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
- dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp;
- priv_interp.env.init(privDictStr);
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
+ if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
+ cff2_priv_dict_interp_env_t env2 (privDictStr);
+ dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init ();
- if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
+ if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
- { fini (); return; }
+ goto fail;
}
- }
- void fini ()
+
+ return;
+
+ fail:
+ _fini ();
+ }
+ ~accelerator_templ_t () { _fini (); }
+ void _fini ()
{
sc.end_processing ();
topDict.fini ();
- fontDicts.fini_deep ();
- privateDicts.fini_deep ();
+ fontDicts.fini ();
+ privateDicts.fini ();
hb_blob_destroy (blob);
blob = nullptr;
}
+ hb_map_t *create_glyph_to_sid_map () const
+ {
+ return nullptr;
+ }
+
bool is_valid () const { return blob; }
protected:
- hb_blob_t *blob;
hb_sanitize_context_t sc;
public:
+ hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict;
- const CFF2Subrs *globalSubrs;
- const CFF2VariationStore *varStore;
- const CFF2CharStrings *charStrings;
- const CFF2FDArray *fdArray;
- const CFF2FDSelect *fdSelect;
- unsigned int fdCount;
+ const CFF2Subrs *globalSubrs = nullptr;
+ const CFF2VariationStore *varStore = nullptr;
+ const CFF2CharStrings *charStrings = nullptr;
+ const CFF2FDArray *fdArray = nullptr;
+ const CFF2FDSelect *fdSelect = nullptr;
+ unsigned int fdCount = 0;
hb_vector_t<cff2_font_dict_values_t> fontDicts;
hb_vector_t<PRIVDICTVAL> privateDicts;
- unsigned int num_glyphs;
+ unsigned int num_glyphs = 0;
};
struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
{
+ accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {}
+
HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const;
-#ifdef HB_EXPERIMENTAL_API
- HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+ HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
};
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
@@ -525,7 +532,10 @@ struct cff2
DEFINE_SIZE_STATIC (5);
};
-struct cff2_accelerator_t : cff2::accelerator_t {};
+struct cff2_accelerator_t : cff2::accelerator_t {
+ cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF2_TABLE_HH */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index c8a2af1e8..523196fa7 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/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;
@@ -93,140 +95,215 @@ struct CmapSubtableFormat0
struct CmapSubtableFormat4
{
+
template<typename Iterator,
+ typename Writer,
hb_requires (hb_is_iterator (Iterator))>
- HBUINT16* serialize_endcode_array (hb_serialize_context_t *c,
- Iterator it)
+ void to_ranges (Iterator it, Writer& range_writer)
{
- HBUINT16 *endCode = c->start_embed<HBUINT16> ();
- hb_codepoint_t prev_endcp = 0xFFFF;
+ hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
+ int run_length = 0 , delta = 0, prev_delta = 0;
- for (const auto& _ : +it)
- {
- if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
+ enum {
+ FIRST_SUB_RANGE,
+ FOLLOWING_SUB_RANGE,
+ } mode;
+
+ while (it) {
+ // Start a new range
{
- HBUINT16 end_code;
- end_code = prev_endcp;
- c->copy<HBUINT16> (end_code);
+ 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;
}
- prev_endcp = _.first;
- }
- {
- // last endCode
- HBUINT16 endcode;
- endcode = prev_endcp;
- if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr;
- // There must be a final entry with end_code == 0xFFFF.
- if (prev_endcp != 0xFFFF)
- {
- HBUINT16 finalcode;
- finalcode = 0xFFFF;
- if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
+ delta = last_gid - start_cp;
+ mode = FIRST_SUB_RANGE;
+ it++;
+
+ while (it) {
+ // Process range
+ 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;
+ }
+
+ if (next_gid == last_gid + 1) {
+ // The current run continues.
+ end_cp = next_cp;
+ run_length++;
+ last_gid = next_gid;
+ it++;
+ continue;
+ }
+
+ // A new run is starting, decide if we want to commit the current run.
+ int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
+ int run_cost = run_length * 2;
+ if (run_cost >= split_cost) {
+ commit_current_range(start_cp,
+ prev_run_start_cp,
+ run_start_cp,
+ end_cp,
+ delta,
+ prev_delta,
+ split_cost,
+ range_writer);
+ start_cp = next_cp;
+ }
+
+ // Start the new run
+ mode = FOLLOWING_SUB_RANGE;
+ prev_run_start_cp = run_start_cp;
+ run_start_cp = next_cp;
+ end_cp = next_cp;
+ prev_delta = delta;
+ delta = next_gid - run_start_cp;
+ run_length = 1;
+ last_gid = next_gid;
+ it++;
}
+
+ // Finalize range
+ commit_current_range (start_cp,
+ prev_run_start_cp,
+ run_start_cp,
+ end_cp,
+ delta,
+ prev_delta,
+ 8,
+ range_writer);
}
- return endCode;
+ if (likely (end_cp != 0xFFFF)) {
+ range_writer (0xFFFF, 0xFFFF, 1);
+ }
}
- template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- HBUINT16* serialize_startcode_array (hb_serialize_context_t *c,
- Iterator it)
- {
- HBUINT16 *startCode = c->start_embed<HBUINT16> ();
- hb_codepoint_t prev_cp = 0xFFFF;
-
- for (const auto& _ : +it)
- {
- if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
- {
- HBUINT16 start_code;
- start_code = _.first;
- c->copy<HBUINT16> (start_code);
+ /*
+ * Writes the current range as either one or two ranges depending on what is most efficient.
+ */
+ template<typename Writer>
+ void commit_current_range (hb_codepoint_t start,
+ hb_codepoint_t prev_run_start,
+ hb_codepoint_t run_start,
+ hb_codepoint_t end,
+ int run_delta,
+ int previous_run_delta,
+ int split_cost,
+ Writer& range_writer) {
+ bool should_split = false;
+ if (start < run_start && run_start < end) {
+ int run_cost = (end - run_start + 1) * 2;
+ if (run_cost >= split_cost) {
+ should_split = true;
}
+ }
- prev_cp = _.first;
+ // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
+ if (should_split) {
+ if (start == prev_run_start)
+ range_writer (start, run_start - 1, previous_run_delta);
+ else
+ range_writer (start, run_start - 1, 0);
+ range_writer (run_start, end, run_delta);
+ return;
}
- // There must be a final entry with end_code == 0xFFFF.
- if (it.len () == 0 || prev_cp != 0xFFFF)
- {
- HBUINT16 finalcode;
- finalcode = 0xFFFF;
- if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
+
+ if (start == run_start) {
+ // Range is only a run
+ range_writer (start, end, run_delta);
+ return;
}
- return startCode;
+ // Write only a single non-run range.
+ range_writer (start, end, 0);
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- HBINT16* serialize_idDelta_array (hb_serialize_context_t *c,
- Iterator it,
- HBUINT16 *endCode,
- HBUINT16 *startCode,
- unsigned segcount)
- {
- unsigned i = 0;
- hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF;
- bool use_delta = true;
-
- HBINT16 *idDelta = c->start_embed<HBINT16> ();
- if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
- return nullptr;
-
- for (const auto& _ : +it)
- {
- if (_.first == startCode[i])
- {
- use_delta = true;
- start_gid = _.second;
+ unsigned serialize_find_segcount (Iterator it) {
+ struct Counter {
+ unsigned segcount = 0;
+
+ void operator() (hb_codepoint_t start,
+ hb_codepoint_t end,
+ int delta) {
+ segcount++;
}
- else if (_.second != last_gid + 1) use_delta = false;
+ } counter;
- if (_.first == endCode[i])
- {
- HBINT16 delta;
- if (use_delta) delta = (int)start_gid - (int)startCode[i];
- else delta = 0;
- c->copy<HBINT16> (delta);
+ to_ranges (+it, counter);
+ return counter.segcount;
+ }
- i++;
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
+ Iterator it,
+ int segcount)
+ {
+ struct Writer {
+ hb_serialize_context_t *serializer_;
+ HBUINT16* end_code_;
+ HBUINT16* start_code_;
+ HBINT16* id_delta_;
+ int index_;
+
+ Writer(hb_serialize_context_t *serializer)
+ : serializer_(serializer),
+ end_code_(nullptr),
+ start_code_(nullptr),
+ id_delta_(nullptr),
+ index_ (0) {}
+ void operator() (hb_codepoint_t start,
+ hb_codepoint_t end,
+ int delta) {
+ start_code_[index_] = start;
+ end_code_[index_] = end;
+ id_delta_[index_] = delta;
+ index_++;
}
+ } writer(c);
- last_gid = _.second;
- last_cp = _.first;
- }
+ writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+ c->allocate_size<HBUINT16> (2); // padding
+ writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+ writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
- if (it.len () == 0 || last_cp != 0xFFFF)
- {
- HBINT16 delta;
- delta = 1;
- if (unlikely (!c->copy<HBINT16> (delta))) return nullptr;
- }
+ if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
- return idDelta;
+ to_ranges (+it, writer);
+ return true;
}
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++)
@@ -251,30 +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;
- //serialize endCode[]
- HBUINT16 *endCode = serialize_endcode_array (c, format4_iter);
- if (unlikely (!endCode)) return;
-
- unsigned segcount = (c->length () - min_size) / HBUINT16::static_size;
+ hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
+ format4_iter
+ };
- // 2 bytes of padding.
- if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding.
-
- // serialize startCode[]
- HBUINT16 *startCode = serialize_startcode_array (c, format4_iter);
- if (unlikely (!startCode)) return;
+ //serialize endCode[], startCode[], idDelta[]
+ HBUINT16* endCode = c->start_embed<HBUINT16> ();
+ unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
+ if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
+ return;
- //serialize idDelta[]
- HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount);
- if (unlikely (!idDelta)) 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;
@@ -305,7 +383,6 @@ struct CmapSubtableFormat4
{
accelerator_t () {}
accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
- ~accelerator_t () { fini (); }
void init (const CmapSubtableFormat4 *subtable)
{
@@ -317,7 +394,6 @@ struct CmapSubtableFormat4
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
}
- void fini () {}
bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
@@ -339,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;
@@ -359,7 +435,7 @@ struct CmapSubtableFormat4
gid += this->idDelta[i];
}
gid &= 0xFFFFu;
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -378,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
@@ -394,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);
}
}
}
@@ -407,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. */
@@ -558,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;
@@ -612,7 +692,7 @@ struct CmapSubtableTrimmed
};
struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
template <typename T>
struct CmapSubtableLongSegmented
@@ -622,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;
@@ -652,7 +732,7 @@ struct CmapSubtableLongSegmented
if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
end = start + (hb_codepoint_t) num_glyphs - gid;
- out->add_range (start, end);
+ out->add_range (start, hb_min (end, 0x10FFFFu));
}
}
@@ -660,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)
{
@@ -716,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;
@@ -756,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)
@@ -837,37 +925,75 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
unsigned init_len = c->length ();
- hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
- int count = -1;
-
- for (const UnicodeValueRange& _ : as_array ())
+ if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
{
- for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+ unicodes->next (&u);)
{
- unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
- if (!unicodes->has (curEntry)) continue;
- count += 1;
- if (lastCode == HB_MAP_VALUE_INVALID)
- lastCode = curEntry;
- else if (lastCode + count != curEntry)
+ if (!as_array ().bsearch (u))
+ continue;
+ if (start == HB_SET_VALUE_INVALID)
{
+ start = u;
+ end = start - 1;
+ }
+ if (end + 1 != u || end - start == 255)
+ {
UnicodeValueRange rec;
- rec.startUnicodeValue = lastCode;
- rec.additionalCount = count - 1;
+ rec.startUnicodeValue = start;
+ rec.additionalCount = end - start;
c->copy<UnicodeValueRange> (rec);
-
- lastCode = curEntry;
- count = 0;
+ start = u;
}
+ end = u;
+ }
+ if (start != HB_SET_VALUE_INVALID)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = start;
+ rec.additionalCount = end - start;
+ c->copy<UnicodeValueRange> (rec);
}
- }
- if (lastCode != HB_MAP_VALUE_INVALID)
+ }
+ else
{
- UnicodeValueRange rec;
- rec.startUnicodeValue = lastCode;
- rec.additionalCount = count;
- c->copy<UnicodeValueRange> (rec);
+ hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
+ int count = -1;
+
+ for (const UnicodeValueRange& _ : *this)
+ {
+ hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
+ hb_codepoint_t end = curEntry + _.additionalCount + 2;
+
+ for (; unicodes->next (&curEntry) && curEntry < end;)
+ {
+ count += 1;
+ if (lastCode == HB_SET_VALUE_INVALID)
+ lastCode = curEntry;
+ else if (lastCode + count != curEntry)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = lastCode;
+ rec.additionalCount = count - 1;
+ c->copy<UnicodeValueRange> (rec);
+
+ lastCode = curEntry;
+ count = 0;
+ }
+ }
+ }
+
+ if (lastCode != HB_MAP_VALUE_INVALID)
+ {
+ UnicodeValueRange rec;
+ rec.startUnicodeValue = lastCode;
+ rec.additionalCount = count;
+ c->copy<UnicodeValueRange> (rec);
+ }
}
if (c->length () - init_len == 0)
@@ -1386,17 +1512,127 @@ struct EncodingRecord
DEFINE_SIZE_STATIC (8);
};
+struct cmap;
+
+struct SubtableUnicodesCache {
+
+ private:
+ hb_blob_ptr_t<cmap> base_blob;
+ const char* base;
+ hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
+
+ public:
+
+ static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
+ {
+ SubtableUnicodesCache* cache =
+ (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
+ new (cache) SubtableUnicodesCache (source_table);
+ return cache;
+ }
+
+ static void destroy (void* value) {
+ if (!value) return;
+
+ SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
+ cache->~SubtableUnicodesCache ();
+ hb_free (cache);
+ }
+
+ SubtableUnicodesCache(const void* cmap_base)
+ : base_blob(),
+ base ((const char*) cmap_base),
+ cached_unicodes ()
+ {}
+
+ SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
+ : base_blob(base_blob_),
+ base ((const char *) base_blob.get()),
+ cached_unicodes ()
+ {}
+
+ ~SubtableUnicodesCache()
+ {
+ base_blob.destroy ();
+ }
+
+ bool same_base(const void* other) const
+ {
+ return other == (const void*) base;
+ }
+
+ const hb_set_t* set_for (const EncodingRecord* record,
+ SubtableUnicodesCache& mutable_cache) const
+ {
+ if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
+ return cached_unicodes.get ((unsigned) ((const char *) record - base));
+
+ return mutable_cache.set_for (record);
+ }
+
+ const hb_set_t* set_for (const EncodingRecord* record)
+ {
+ if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
+ {
+ 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 ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
+ return hb_set_get_empty ();
+
+ return s;
+ }
+ return cached_unicodes.get ((unsigned) ((const char *) record - base));
+ }
+
+};
+
+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;
+
+ static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
+ const cmap* cmap = source_table.get();
+ auto it =
+ + hb_iter (cmap->encodingRecord)
+ | hb_filter ([&](const EncodingRecord& _) {
+ return cmap::filter_encoding_records_for_subset (cmap, _);
+ })
+ ;
+
+ SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
+ for (const EncodingRecord& _ : it)
+ cache->set_for(&_); // populate the cache for this encoding record.
+
+ return cache;
+ }
+
template<typename Iterator, typename EncodingRecIter,
hb_requires (hb_is_iterator (EncodingRecIter))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
EncodingRecIter encodingrec_iter,
const void *base,
- const hb_subset_plan_t *plan,
+ hb_subset_plan_t *plan,
bool drop_format_4 = false)
{
if (unlikely (!c->extend_min ((*this)))) return false;
@@ -1405,6 +1641,14 @@ struct cmap
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
auto snap = c->snapshot ();
+ SubtableUnicodesCache local_unicodes_cache (base);
+ const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
+
+ if (plan->accelerator &&
+ plan->accelerator->cmap_cache &&
+ plan->accelerator->cmap_cache->same_base (base))
+ unicodes_cache = plan->accelerator->cmap_cache;
+
for (const EncodingRecord& _ : encodingrec_iter)
{
if (c->in_error ())
@@ -1413,12 +1657,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);
+ const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
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.
@@ -1433,8 +1676,14 @@ 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,
+ local_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);
}
@@ -1452,6 +1701,8 @@ struct cmap
bool _can_drop (const EncodingRecord& cmap12,
const hb_set_t& cmap12_unicodes,
const void* base,
+ const SubtableUnicodesCache& unicodes_cache,
+ SubtableUnicodesCache& local_unicodes_cache,
Iterator subset_unicodes,
EncodingRecordIterator encoding_records)
{
@@ -1482,11 +1733,10 @@ struct cmap
|| (base+_.subtable).get_language() != target_language)
continue;
- hb_set_t sibling_unicodes;
- (base+_.subtable).collect_unicodes (&sibling_unicodes);
+ const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
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;
@@ -1520,17 +1770,9 @@ struct cmap
auto encodingrec_iter =
+ hb_iter (encodingRecord)
- | hb_filter ([&] (const EncodingRecord& _)
- {
- if ((_.platformID == 0 && _.encodingID == 3) ||
- (_.platformID == 0 && _.encodingID == 4) ||
- (_.platformID == 3 && _.encodingID == 1) ||
- (_.platformID == 3 && _.encodingID == 10) ||
- (this + _.subtable).u.format == 14)
- return true;
-
- return false;
- })
+ | hb_filter ([&](const EncodingRecord& _) {
+ return cmap::filter_encoding_records_for_subset (this, _);
+ })
;
if (unlikely (!encodingrec_iter.len ())) return_trace (false);
@@ -1543,7 +1785,7 @@ struct cmap
unsigned format = (this + _.subtable).u.format;
if (format == 12) has_format12 = true;
- const EncodingRecord *table = hb_addressof (_);
+ const EncodingRecord *table = std::addressof (_);
if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table;
else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table;
else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table;
@@ -1554,18 +1796,16 @@ 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); })
;
- return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
+ return_trace (cmap_prime->serialize (c->serializer,
+ it,
+ encodingrec_iter,
+ this,
+ c->plan));
}
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -1601,7 +1841,7 @@ struct cmap
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
bool symbol;
@@ -1615,7 +1855,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) {
@@ -1636,8 +1893,7 @@ struct cmap
}
}
}
-
- void fini () { this->table.destroy (); }
+ ~accelerator_t () { this->table.destroy (); }
bool get_nominal_glyph (hb_codepoint_t unicode,
hb_codepoint_t *glyph) const
@@ -1698,6 +1954,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,
@@ -1708,7 +1965,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)
@@ -1717,15 +1974,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;
}
@@ -1791,6 +2041,19 @@ struct cmap
encodingRecord.sanitize (c, this));
}
+ private:
+
+ static bool filter_encoding_records_for_subset(const cmap* cmap,
+ const EncodingRecord& _)
+ {
+ return
+ (_.platformID == 0 && _.encodingID == 3) ||
+ (_.platformID == 0 && _.encodingID == 4) ||
+ (_.platformID == 3 && _.encodingID == 1) ||
+ (_.platformID == 3 && _.encodingID == 10) ||
+ (cmap + _.subtable).u.format == 14;
+ }
+
protected:
HBUINT16 version; /* Table version number (0). */
SortedArray16Of<EncodingRecord>
@@ -1799,7 +2062,9 @@ struct cmap
DEFINE_SIZE_ARRAY (4, encodingRecord);
};
-struct cmap_accelerator_t : cmap::accelerator_t {};
+struct cmap_accelerator_t : cmap::accelerator_t {
+ cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 14459914e..3246894d3 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -67,7 +67,7 @@ _copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
{
unsigned int new_len = cbdt_prime->length + length;
if (unlikely (!cbdt_prime->alloc (new_len))) return false;
- memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
+ hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
cbdt_prime->length = new_len;
return true;
}
@@ -360,6 +360,16 @@ struct IndexSubtable
struct IndexSubtableRecord
{
+ /* XXX Remove this and fix by not inserting it into vector. */
+ IndexSubtableRecord& operator = (const IndexSubtableRecord &o)
+ {
+ firstGlyphIndex = o.firstGlyphIndex;
+ lastGlyphIndex = o.lastGlyphIndex;
+ offsetToSubtable = (unsigned) o.offsetToSubtable;
+ assert (offsetToSubtable.is_null ());
+ return *this;
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -458,13 +468,13 @@ struct IndexSubtableRecord
if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
return_trace (false);
- (*records)[records->length - 1].firstGlyphIndex = 1;
- (*records)[records->length - 1].lastGlyphIndex = 0;
+ records->tail ().firstGlyphIndex = 1;
+ records->tail ().lastGlyphIndex = 0;
bitmap_size_context->size += IndexSubtableRecord::min_size;
c->serializer->push ();
- if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start)))
+ if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start)))
{
c->serializer->pop_discard ();
c->serializer->revert (snap);
@@ -809,15 +819,14 @@ struct CBDT
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
- cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
- cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);
+ this->cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
+ this->cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);
upem = hb_face_get_upem (face);
}
-
- void fini ()
+ ~accelerator_t ()
{
this->cblc.destroy ();
this->cbdt.destroy ();
@@ -978,7 +987,10 @@ CBLC::subset (hb_subset_context_t *c) const
return_trace (CBLC::sink_cbdt (c, &cbdt_prime));
}
-struct CBDT_accelerator_t : CBDT::accelerator_t {};
+struct CBDT_accelerator_t : CBDT::accelerator_t {
+ CBDT_accelerator_t (hb_face_t *face) : CBDT::accelerator_t (face) {}
+};
+
} /* namespace OT */
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index 03476faba..1af9d3093 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -38,12 +38,8 @@
*/
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
-#ifndef COLRV1_MAX_NESTING_LEVEL
-#define COLRV1_MAX_NESTING_LEVEL 100
-#endif
-
-#ifndef COLRV1_ENABLE_SUBSETTING
-#define COLRV1_ENABLE_SUBSETTING 1
+#ifndef HB_COLRV1_MAX_NESTING_LEVEL
+#define HB_COLRV1_MAX_NESTING_LEVEL 16
#endif
namespace OT {
@@ -71,7 +67,7 @@ struct hb_colrv1_closure_context_t :
bool paint_visited (const void *paint)
{
hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
- if (visited_paint.has (delta))
+ if (visited_paint.in_error() || visited_paint.has (delta))
return true;
visited_paint.add (delta);
@@ -102,7 +98,7 @@ struct hb_colrv1_closure_context_t :
hb_set_t *glyphs_,
hb_set_t *layer_indices_,
hb_set_t *palette_indices_,
- unsigned nesting_level_left_ = COLRV1_MAX_NESTING_LEVEL) :
+ unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) :
base (base_),
glyphs (glyphs_),
layer_indices (layer_indices_),
@@ -145,7 +141,7 @@ struct BaseGlyphRecord
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
public:
@@ -188,6 +184,7 @@ struct Variable
protected:
T value;
+ public:
VarIdx varIdxBase;
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
@@ -196,6 +193,8 @@ struct Variable
template <typename T>
struct NoVariable
{
+ static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
+
NoVariable<T>* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@@ -358,14 +357,14 @@ struct Affine2x3
return_trace (c->check_struct (this));
}
- HBFixed xx;
- HBFixed yx;
- HBFixed xy;
- HBFixed yy;
- HBFixed dx;
- HBFixed dy;
+ F16DOT16 xx;
+ F16DOT16 yx;
+ F16DOT16 xy;
+ F16DOT16 yy;
+ F16DOT16 dx;
+ F16DOT16 dy;
public:
- DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
+ DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
};
struct PaintColrLayers
@@ -524,6 +523,7 @@ struct PaintSweepGradient
};
struct Paint;
+
// Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph
{
@@ -887,6 +887,11 @@ struct PaintComposite
DEFINE_SIZE_STATIC (8);
};
+struct ClipBoxData
+{
+ int xMin, yMin, xMax, yMax;
+};
+
struct ClipBoxFormat1
{
bool sanitize (hb_sanitize_context_t *c) const
@@ -895,6 +900,14 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this));
}
+ void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+ {
+ clip_box.xMin = xMin;
+ clip_box.yMin = yMin;
+ clip_box.xMax = xMax;
+ clip_box.yMax = yMax;
+ }
+
public:
HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
FWORD xMin;
@@ -905,7 +918,20 @@ struct ClipBoxFormat1
DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
};
-struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {};
+struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
+{
+ void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+ {
+ value.get_clip_box(clip_box, instancer);
+ if (instancer)
+ {
+ clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0));
+ clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1));
+ clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2));
+ clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3));
+ }
+ }
+};
struct ClipBox
{
@@ -931,6 +957,28 @@ struct ClipBox
}
}
+ bool get_extents (hb_glyph_extents_t *extents,
+ const VarStoreInstancer &instancer) const
+ {
+ ClipBoxData clip_box;
+ switch (u.format) {
+ case 1:
+ u.format1.get_clip_box (clip_box, instancer);
+ break;
+ case 2:
+ u.format2.get_clip_box (clip_box, instancer);
+ break;
+ default:
+ return false;
+ }
+
+ extents->x_bearing = clip_box.xMin;
+ extents->y_bearing = clip_box.yMax;
+ extents->width = clip_box.xMax - clip_box.xMin;
+ extents->height = clip_box.yMin - clip_box.yMax;
+ return true;
+ }
+
protected:
union {
HBUINT8 format; /* Format identifier */
@@ -941,6 +989,9 @@ struct ClipBox
struct ClipRecord
{
+ int cmp (hb_codepoint_t g) const
+ { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
+
ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
{
TRACE_SERIALIZE (this);
@@ -956,6 +1007,13 @@ struct ClipRecord
return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
}
+ bool get_extents (hb_glyph_extents_t *extents,
+ const void *base,
+ const VarStoreInstancer &instancer) const
+ {
+ return (base+clipBox).get_extents (extents, instancer);
+ }
+
public:
HBUINT16 startGlyphID; // first gid clip applies to
HBUINT16 endGlyphID; // last gid clip applies to, inclusive
@@ -963,6 +1021,7 @@ struct ClipRecord
public:
DEFINE_SIZE_STATIC (7);
};
+DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
@@ -985,7 +1044,7 @@ struct ClipList
for (const hb_codepoint_t _ : gids.iter ())
{
if (_ == start_gid) continue;
-
+
offset = gid_offset_map.get (_);
if (_ == prev_gid + 1 && offset == prev_offset)
{
@@ -1025,9 +1084,9 @@ struct ClipList
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
- const hb_set_t& glyphset = *c->plan->_glyphset;
+ const hb_set_t& glyphset = *c->plan->_glyphset_colred;
const hb_map_t &glyph_map = *c->plan->glyph_map;
-
+
hb_map_t new_gid_offset_map;
hb_set_t new_gids;
for (const ClipRecord& record : clips.iter ())
@@ -1051,17 +1110,44 @@ struct ClipList
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+ // TODO Make a formatted struct!
return_trace (c->check_struct (this) && clips.sanitize (c, this));
}
+ bool
+ get_extents (hb_codepoint_t gid,
+ hb_glyph_extents_t *extents,
+ const VarStoreInstancer &instancer) const
+ {
+ auto *rec = clips.as_array ().bsearch (gid);
+ if (rec)
+ {
+ rec->get_extents (extents, this, instancer);
+ return true;
+ }
+ return false;
+ }
+
HBUINT8 format; // Set to 1.
- Array32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
+ SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
public:
DEFINE_SIZE_ARRAY_SIZED (5, clips);
};
struct Paint
{
+
+ template <typename ...Ts>
+ bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
+ {
+ TRACE_SANITIZE (this);
+
+ if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL)))
+ return_trace (c->no_dispatch_return_value ());
+
+ return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -1140,6 +1226,8 @@ struct Paint
Variable<PaintSkewAroundCenter> paintformat31;
PaintComposite paintformat32;
} u;
+ public:
+ DEFINE_SIZE_MIN (2);
};
struct BaseGlyphPaintRecord
@@ -1181,7 +1269,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- const hb_set_t* glyphset = c->plan->_glyphset;
+ const hb_set_t* glyphset = c->plan->_glyphset_colred;
for (const auto& _ : as_array ())
{
@@ -1258,13 +1346,9 @@ struct COLR
struct accelerator_t
{
- accelerator_t () {}
- ~accelerator_t () { fini (); }
-
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{ colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
-
- void fini () { this->colr.destroy (); }
+ ~accelerator_t () { this->colr.destroy (); }
bool is_valid () { return colr.get_blob ()->length; }
@@ -1348,7 +1432,7 @@ struct COLR
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers) &&
(version == 0 ||
- (COLRV1_ENABLE_SUBSETTING && version == 1 &&
+ (version == 1 &&
baseGlyphList.sanitize (c, this) &&
layerList.sanitize (c, this) &&
clipList.sanitize (c, this) &&
@@ -1399,10 +1483,9 @@ struct COLR
const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
{
- if ((unsigned int) gid == 0) // Ignore notdef.
- return nullptr;
const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
- if ((record && (hb_codepoint_t) record->glyphId != gid))
+ if (record == &Null (BaseGlyphRecord) ||
+ (record && (hb_codepoint_t) record->glyphId != gid))
record = nullptr;
return record;
}
@@ -1420,9 +1503,16 @@ struct COLR
TRACE_SUBSET (this);
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+ const hb_set_t& glyphset = *c->plan->_glyphset_colred;
auto base_it =
+ hb_range (c->plan->num_output_glyphs ())
+ | hb_filter ([&](hb_codepoint_t new_gid)
+ {
+ hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+ if (glyphset.has (old_gid)) return true;
+ return false;
+ })
| hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
@@ -1430,7 +1520,6 @@ struct COLR
const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
if (unlikely (!old_record))
return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
-
BaseGlyphRecord new_record = {};
new_record.glyphId = new_gid;
new_record.numLayers = old_record->numLayers;
@@ -1443,6 +1532,7 @@ struct COLR
auto layer_it =
+ hb_range (c->plan->num_output_glyphs ())
| hb_map (reverse_glyph_map)
+ | hb_filter (glyphset)
| hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
{
const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
@@ -1499,6 +1589,30 @@ struct COLR
return_trace (true);
}
+ bool
+ get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+ {
+ if (version != 1)
+ return false;
+
+ VarStoreInstancer instancer (this+varStore,
+ this+varIdxMap,
+ hb_array (font->coords, font->num_coords));
+
+ if ((this+clipList).get_extents (glyph,
+ extents,
+ instancer))
+ {
+ extents->x_bearing = font->em_scale_x (extents->x_bearing);
+ extents->y_bearing = font->em_scale_x (extents->y_bearing);
+ extents->width = font->em_scale_x (extents->width);
+ extents->height = font->em_scale_x (extents->height);
+ return true;
+ }
+
+ return false;
+ }
+
protected:
HBUINT16 version; /* Table version number (starts at 0). */
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
@@ -1517,6 +1631,10 @@ struct COLR
DEFINE_SIZE_MIN (14);
};
+struct COLR_accelerator_t : COLR::accelerator_t {
+ COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
+};
+
} /* namespace OT */
diff --git a/src/hb-ot-color-colrv1-closure.hh b/src/hb-ot-color-colrv1-closure.hh
index ca85ba6ad..fbaf2ec26 100644
--- a/src/hb-ot-color-colrv1-closure.hh
+++ b/src/hb-ot-color-colrv1-closure.hh
@@ -43,7 +43,7 @@ HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) con
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
- const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i];
+ const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i];
paint.dispatch (c);
}
}
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index a9deeba9a..bcab77f79 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/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/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index d2911f19e..d0e2235fb 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -202,12 +202,12 @@ struct sbix
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<sbix> (face);
num_glyphs = face->get_num_glyphs ();
}
- void fini () { table.destroy (); }
+ ~accelerator_t () { table.destroy (); }
bool has_data () const { return table->has_data (); }
@@ -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;
@@ -407,7 +413,10 @@ struct sbix
DEFINE_SIZE_ARRAY (8, strikes);
};
-struct sbix_accelerator_t : sbix::accelerator_t {};
+struct sbix_accelerator_t : sbix::accelerator_t {
+ sbix_accelerator_t (hb_face_t *face) : sbix::accelerator_t (face) {}
+};
+
} /* namespace OT */
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index e022ef43b..fc649f100 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -79,9 +79,9 @@ struct SVG
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{ table = hb_sanitize_context_t ().reference_table<SVG> (face); }
- void fini () { table.destroy (); }
+ ~accelerator_t () { table.destroy (); }
hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
{
@@ -116,7 +116,9 @@ struct SVG
DEFINE_SIZE_STATIC (10);
};
-struct SVG_accelerator_t : SVG::accelerator_t {};
+struct SVG_accelerator_t : SVG::accelerator_t {
+ SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 4170b7131..696ca3e17 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -61,7 +61,7 @@
*
* Tests whether a face includes a `CPAL` color-palette table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.1.0
*/
@@ -90,15 +90,15 @@ hb_ot_color_palette_get_count (hb_face_t *face)
/**
* hb_ot_color_palette_get_name_id:
* @face: #hb_face_t to work upon
- * @palette_index: The index of the color palette
+ * @palette_index: The index of the color palette
*
* Fetches the `name` table Name ID that provides display names for
- * a `CPAL` color palette.
+ * a `CPAL` color palette.
*
* Palette display names can be generic (e.g., "Default") or provide
* specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").
*
- * Return value: the Named ID found for the palette.
+ * Return value: the Named ID found for the palette.
* If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
*
* Since: 2.1.0
@@ -116,7 +116,7 @@ hb_ot_color_palette_get_name_id (hb_face_t *face,
* @color_index: The index of the color
*
* Fetches the `name` table Name ID that provides display names for
- * the specificed color in a face's `CPAL` color palette.
+ * the specified color in a face's `CPAL` color palette.
*
* Display names can be generic (e.g., "Background") or specific
* (e.g., "Eye color").
@@ -192,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
*
* Tests whether a face includes any `COLR` color layers.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.1.0
*/
@@ -239,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
*
* Tests whether a face includes any `SVG` glyph images.
*
- * Return value: %true if data found, %false otherwise.
+ * Return value: `true` if data found, `false` otherwise.
*
* Since: 2.1.0
*/
@@ -256,6 +256,8 @@ hb_ot_color_has_svg (hb_face_t *face)
*
* Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded.
*
+ * If the glyph has no SVG document, the singleton empty blob is returned.
+ *
* Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available
*
* Since: 2.1.0
@@ -277,7 +279,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
*
* Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.1.0
*/
@@ -293,8 +295,10 @@ hb_ot_color_has_png (hb_face_t *face)
* @glyph: a glyph index
*
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
- * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
- * object. If UPEM is unset, the blob returned will be the largest PNG available.
+ * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
+ * object. If PPEM is unset, the blob returned will be the largest PNG available.
+ *
+ * If the glyph has no PNG image, the singleton empty blob is returned.
*
* Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available
*
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
index c23ce4de4..d11e07e23 100644
--- a/src/hb-ot-color.h
+++ b/src/hb-ot-color.h
@@ -102,6 +102,10 @@ hb_ot_color_has_layers (hb_face_t *face);
*
* Pairs of glyph and color index.
*
+ * A color index of 0xFFFF does not refer to a palette
+ * color, but indicates that the foreground color should
+ * be used.
+ *
* Since: 2.1.0
**/
typedef struct hb_ot_color_layer_t {
diff --git a/src/hb-ot-deprecated.h b/src/hb-ot-deprecated.h
index ce6b6fef1..5192ff73e 100644
--- a/src/hb-ot-deprecated.h
+++ b/src/hb-ot-deprecated.h
@@ -50,6 +50,21 @@ HB_BEGIN_DECLS
*/
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
+/* https://github.com/harfbuzz/harfbuzz/pull/3417 */
+/**
+ * HB_OT_MATH_SCRIPT:
+ *
+ * Use #HB_SCRIPT_MATH or #HB_OT_TAG_MATH_SCRIPT instead.
+ *
+ * <note>Previous versions of this documentation recommended passing
+ * #HB_OT_MATH_SCRIPT to hb_buffer_set_script() to enable math shaping, but this
+ * usage is no longer supported. Use #HB_SCRIPT_MATH instead.</note>
+ *
+ * Since: 1.3.3
+ * Deprecated: 3.4.0
+ */
+#define HB_OT_MATH_SCRIPT HB_OT_TAG_MATH_SCRIPT
+
/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh
index ffbbb1bc5..c9da36c1b 100644
--- a/src/hb-ot-face-table-list.hh
+++ b/src/hb-ot-face-table-list.hh
@@ -32,6 +32,11 @@
#define HB_OT_FACE_TABLE_LIST_HH
#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
+#ifndef HB_OT_CORE_TABLE
+#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_CORE_TABLE_UNDEF
+#endif
+
#ifndef HB_OT_ACCELERATOR
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
#define _HB_OT_ACCELERATOR_UNDEF
@@ -46,13 +51,14 @@
/* OpenType fundamentals. */
-HB_OT_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, maxp)
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
HB_OT_ACCELERATOR (OT, cmap)
#endif
-HB_OT_TABLE (OT, hhea)
+HB_OT_CORE_TABLE (OT, hhea)
HB_OT_ACCELERATOR (OT, hmtx)
-HB_OT_TABLE (OT, OS2)
+HB_OT_CORE_TABLE (OT, OS2)
#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
HB_OT_ACCELERATOR (OT, post)
#endif
@@ -60,37 +66,40 @@ HB_OT_ACCELERATOR (OT, post)
HB_OT_ACCELERATOR (OT, name)
#endif
#ifndef HB_NO_STYLE
-HB_OT_TABLE (OT, STAT)
+HB_OT_CORE_TABLE (OT, STAT)
#endif
#ifndef HB_NO_META
HB_OT_ACCELERATOR (OT, meta)
#endif
/* Vertical layout. */
-HB_OT_TABLE (OT, vhea)
+#ifndef HB_NO_VERTICAL
+HB_OT_CORE_TABLE (OT, vhea)
HB_OT_ACCELERATOR (OT, vmtx)
+HB_OT_CORE_TABLE (OT, VORG)
+#endif
/* TrueType outlines. */
+HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs
HB_OT_ACCELERATOR (OT, glyf)
/* CFF outlines. */
#ifndef HB_NO_CFF
HB_OT_ACCELERATOR (OT, cff1)
HB_OT_ACCELERATOR (OT, cff2)
-HB_OT_TABLE (OT, VORG)
#endif
/* OpenType variations. */
#ifndef HB_NO_VAR
-HB_OT_TABLE (OT, fvar)
-HB_OT_TABLE (OT, avar)
+HB_OT_CORE_TABLE (OT, fvar)
+HB_OT_CORE_TABLE (OT, avar)
HB_OT_ACCELERATOR (OT, gvar)
-HB_OT_TABLE (OT, MVAR)
+HB_OT_CORE_TABLE (OT, MVAR)
#endif
/* Legacy kern. */
#ifndef HB_NO_OT_KERN
-HB_OT_TABLE (OT, kern)
+HB_OT_CORE_TABLE (OT, kern)
#endif
/* OpenType shaping. */
@@ -98,12 +107,12 @@ HB_OT_TABLE (OT, kern)
HB_OT_ACCELERATOR (OT, GDEF)
HB_OT_ACCELERATOR (OT, GSUB)
HB_OT_ACCELERATOR (OT, GPOS)
-//HB_OT_TABLE (OT, JSTF)
+//HB_OT_CORE_TABLE (OT, JSTF)
#endif
/* OpenType baseline. */
#ifndef HB_NO_BASE
-HB_OT_TABLE (OT, BASE)
+HB_OT_CORE_TABLE (OT, BASE)
#endif
/* AAT shaping. */
@@ -120,8 +129,8 @@ HB_OT_TABLE (AAT, feat)
/* OpenType color fonts. */
#ifndef HB_NO_COLOR
-HB_OT_TABLE (OT, COLR)
-HB_OT_TABLE (OT, CPAL)
+HB_OT_CORE_TABLE (OT, COLR)
+HB_OT_CORE_TABLE (OT, CPAL)
HB_OT_ACCELERATOR (OT, CBDT)
HB_OT_ACCELERATOR (OT, sbix)
HB_OT_ACCELERATOR (OT, SVG)
@@ -129,10 +138,14 @@ HB_OT_ACCELERATOR (OT, SVG)
/* OpenType math. */
#ifndef HB_NO_MATH
-HB_OT_TABLE (OT, MATH)
+HB_OT_CORE_TABLE (OT, MATH)
#endif
#ifdef _HB_OT_ACCELERATOR_UNDEF
#undef HB_OT_ACCELERATOR
#endif
+
+#ifdef _HB_OT_CORE_TABLE_UNDEF
+#undef HB_OT_CORE_TABLE
+#endif
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index e24d380bc..415dae8e2 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -63,10 +63,13 @@ struct hb_ot_face_t
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_TABLE(Namespace, Type) \
hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
+#define HB_OT_CORE_TABLE(Namespace, Type) \
+ hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type;
#define HB_OT_ACCELERATOR(Namespace, Type) \
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
#include "hb-ot-face-table-list.hh"
#undef HB_OT_ACCELERATOR
+#undef HB_OT_CORE_TABLE
#undef HB_OT_TABLE
};
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 5c044c1c4..840510342 100644
--- a/src/hb-ot-font.cc
+++ b/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"
@@ -39,12 +40,12 @@
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
-#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-vorg-table.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-colr-table.hh"
/**
@@ -58,6 +59,43 @@
* never need to call these functions directly.
**/
+using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
+
+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_ot_font_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 +104,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 +119,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 +134,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,17 +148,86 @@ 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::HVAR &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_ot_font_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_acquire ();
+ if (unlikely (!cache))
+ {
+ cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_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_release (font->serial_coords);
+ }
+ }
+ out:
+
+ if (!use_cache)
+ {
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*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_acquire () != (int) font->serial_coords)
+ {
+ ot_font->advance_cache->init ();
+ ot_font->cached_coords_serial.set_release (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_with_var_unscaled (*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
static void
hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
unsigned count,
@@ -127,17 +237,48 @@ 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;
- for (unsigned int i = 0; i < count; i++)
+ if (vmtx.has_data ())
+ {
+#ifndef HB_NO_VAR
+ const OT::VVAR &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_with_var_unscaled (*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
{
- *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
- first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
- first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+ hb_font_extents_t font_extents;
+ font->get_h_extents_with_fallback (&font_extents);
+ hb_position_t advance = -(font_extents.ascender - font_extents.descender);
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *first_advance = advance;
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+ }
}
}
+#endif
+#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_ot_get_glyph_v_origin (hb_font_t *font,
void *font_data,
@@ -146,25 +287,45 @@ 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;
-#ifndef HB_NO_OT_FONT_CFF
const OT::VORG &VORG = *ot_face->VORG;
if (VORG.has_data ())
{
- *y = font->em_scale_y (VORG.get_y_origin (glyph));
+ float delta = 0;
+
+#ifndef HB_NO_VAR
+ const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+ const OT::VVAR &VVAR = *vmtx.var_table;
+ if (font->num_coords)
+ VVAR.get_vorg_delta_unscaled (glyph,
+ font->coords, font->num_coords,
+ &delta);
+#endif
+
+ *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
return true;
}
-#endif
hb_glyph_extents_t extents = {0};
if (ot_face->glyf->get_extents (font, glyph, &extents))
{
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
- hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
- *y = extents.y_bearing + font->em_scale_y (tsb);
+ int tsb = 0;
+ if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
+ {
+ *y = extents.y_bearing + font->em_scale_y (tsb);
+ return true;
+ }
+
+ hb_font_extents_t font_extents;
+ font->get_h_extents_with_fallback (&font_extents);
+ hb_position_t advance = font_extents.ascender - font_extents.descender;
+ int diff = advance - -extents.height;
+ *y = extents.y_bearing + (diff >> 1);
return true;
}
@@ -174,6 +335,7 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
return true;
}
+#endif
static hb_bool_t
hb_ot_get_glyph_extents (hb_font_t *font,
@@ -182,21 +344,22 @@ 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;
+ if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
+#endif
+#if !defined(HB_NO_COLOR)
+ if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
#endif
-#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
- if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
-#endif
- // TODO Hook up side-bearings variations.
return false;
}
@@ -208,7 +371,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;
@@ -222,7 +387,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;
@@ -242,6 +409,7 @@ hb_ot_get_font_h_extents (hb_font_t *font,
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
}
+#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_ot_get_font_v_extents (hb_font_t *font,
void *font_data HB_UNUSED,
@@ -252,6 +420,24 @@ hb_ot_get_font_v_extents (hb_font_t *font,
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
}
+#endif
+
+#ifndef HB_NO_DRAW
+static void
+hb_ot_get_glyph_shape (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data)
+{
+ hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
+ if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
+#ifndef HB_NO_CFF
+ if (font->face->table.cff1->get_path (font, glyph, draw_session)) return;
+ if (font->face->table.cff2->get_path (font, glyph, draw_session)) return;
+#endif
+}
+#endif
static inline void free_static_ot_funcs ();
@@ -261,17 +447,27 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
- hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
- hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
+
+ hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+ hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
+#ifndef HB_NO_DRAW
+ hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr);
+#endif
+
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
+
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
@@ -309,23 +505,28 @@ _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
-int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
+ int *lsb)
{
- return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
+ return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
}
unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
{
- return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+ return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
}
#endif
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 6b419ea1a..c32ff7636 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -30,1302 +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)
- {
- unsigned max_offset =
- + padded_offsets
- | hb_reduce (hb_add, 0)
- ;
- unsigned num_offsets = padded_offsets.len () + 1;
- bool use_short_loca = max_offset < 0x1FFFF;
- 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 "
- "max_offset %d size %d",
- entry_size, num_offsets, max_offset, 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,
- const hb_subset_plan_t *plan)
- {
- TRACE_SERIALIZE (this);
- unsigned init_len = c->length ();
- for (const auto &_ : it) _.serialize (c, 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);
-
- glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
-
- auto padded_offsets =
- + hb_iter (glyphs)
- | hb_map (&SubsetGlyph::padded_size)
- ;
-
- if (unlikely (c->serializer->in_error ())) return_trace (false);
- return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
- padded_offsets)));
- }
-
- 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;
- glyf.init (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)
- ;
-
- glyf.fini ();
- }
-
- 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 (length (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 + glyf_accelerator.vmtx->get_side_bearing (gid);
- unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
- unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid);
- 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
- if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
- return false;
-#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
- {
- void init (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;
- vmtx = nullptr;
- face = face_;
- const OT::head &head = *face->table.head;
- if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
- /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
- return;
- short_offset = 0 == head.indexToLocFormat;
-
- loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
- glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
-#ifndef HB_NO_VAR
- gvar = face->table.gvar;
-#endif
- hmtx = face->table.hmtx;
- vmtx = face->table.vmtx;
-
- num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
- num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
- }
-
- void fini ()
- {
- loca_table.destroy ();
- 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 is_vertical ? vmtx->get_advance (gid) : 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 is_vertical ? vmtx->get_side_bearing (gid) : 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;
- }
-
-#ifdef HB_EXPERIMENTAL_API
- struct path_builder_t
- {
- hb_font_t *font;
- draw_helper_t *draw_helper;
-
- 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_, draw_helper_t &draw_helper_)
- {
- font = font_;
- draw_helper = &draw_helper_;
- 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)
- {
- /* Skip empty contours */
- if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
- return;
-
- bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
- optional_point_t p (point.x, point.y);
- if (!first_oncurve.has_data)
- {
- if (is_on_curve)
- {
- first_oncurve = p;
- draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_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_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
- }
- else
- first_offcurve = p;
- }
- }
- else
- {
- if (last_offcurve.has_data)
- {
- if (is_on_curve)
- {
- draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
- font->em_scalef_x (p.x), font->em_scalef_y (p.y));
- last_offcurve = optional_point_t ();
- }
- else
- {
- optional_point_t mid = last_offcurve.lerp (p, .5f);
- draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
- font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
- last_offcurve = p;
- }
- }
- else
- {
- if (is_on_curve)
- draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_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_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
- font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
- last_offcurve = optional_point_t ();
- /* now check the rest */
- }
-
- if (first_offcurve.has_data && first_oncurve.has_data)
- draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
- font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
- else if (last_offcurve.has_data && first_oncurve.has_data)
- draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
- font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
- else if (first_oncurve.has_data)
- draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
-
- /* Getting ready for the next contour */
- first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
- draw_helper->end_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, draw_helper_t &draw_helper) const
- { return get_points (font, gid, path_builder_t (font, draw_helper)); }
-#endif
-
-#ifndef HB_NO_VAR
- const gvar_accelerator_t *gvar;
-#endif
- const hmtx_accelerator_t *hmtx;
- const vmtx_accelerator_t *vmtx;
-
- private:
- bool short_offset;
- unsigned int num_glyphs;
- hb_blob_ptr_t<loca> loca_table;
- hb_blob_ptr_t<glyf> glyf_table;
- hb_face_t *face;
- };
-
- 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,
- 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 = padding ();
- 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 {};
-
-} /* namespace OT */
-
+#include "OT/glyf/glyf.hh"
#endif /* HB_OT_GLYF_TABLE_HH */
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 403832993..96a394ba4 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -28,6 +28,7 @@
#define HB_OT_HMTX_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-ot-maxp-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-metrics.hh"
@@ -42,11 +43,11 @@
#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
-HB_INTERNAL int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+HB_INTERNAL bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
HB_INTERNAL unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
namespace OT {
@@ -61,7 +62,7 @@ struct LongMetric
};
-template <typename T, typename H>
+template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
struct hmtxvmtx
{
bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
@@ -72,6 +73,8 @@ struct hmtxvmtx
return_trace (true);
}
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
+ { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; }
bool subset_update_header (hb_subset_plan_t *plan,
unsigned int num_hmetrics) const
@@ -98,12 +101,12 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
- unsigned num_advances)
+ unsigned num_long_metrics)
{
unsigned idx = 0;
for (auto _ : it)
{
- if (idx < num_advances)
+ if (idx < num_long_metrics)
{
LongMetric lm;
lm.advance = _.first;
@@ -127,30 +130,46 @@ struct hmtxvmtx
T *table_prime = c->serializer->start_embed <T> ();
if (unlikely (!table_prime)) return_trace (false);
- accelerator_t _mtx;
- _mtx.init (c->plan->source);
- unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
+ accelerator_t _mtx (c->plan->source);
+ unsigned num_long_metrics;
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
+ {
+ /* Determine num_long_metrics to encode. */
+ auto& plan = c->plan;
+
+ num_long_metrics = plan->num_output_glyphs ();
+ unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
+ while (num_long_metrics > 1 &&
+ last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
+ {
+ num_long_metrics--;
+ }
+ }
auto it =
+ hb_range (c->plan->num_output_glyphs ())
- | hb_map ([c, &_mtx] (unsigned _)
+ | hb_map ([c, &_mtx, mtx_map] (unsigned _)
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (_, &old_gid))
- return hb_pair (0u, 0);
- return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+ if (!mtx_map->has (_))
+ {
+ hb_codepoint_t old_gid;
+ if (!c->plan->old_gid_for_new_gid (_, &old_gid))
+ return hb_pair (0u, 0);
+ int lsb = 0;
+ (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
+ return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
+ }
+ return mtx_map->get (_);
})
;
- table_prime->serialize (c->serializer, it, num_advances);
-
- _mtx.fini ();
+ table_prime->serialize (c->serializer, it, num_long_metrics);
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics
- if (unlikely (!subset_update_header (c->plan, num_advances)))
+ if (unlikely (!subset_update_header (c->plan, num_long_metrics)))
return_trace (false);
return_trace (true);
@@ -160,138 +179,182 @@ struct hmtxvmtx
{
friend struct hmtxvmtx;
- void init (hb_face_t *face,
- unsigned int default_advance_ = 0)
+ accelerator_t (hb_face_t *face)
{
- default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
+ table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+ var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
- num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
+ default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
- table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+ /* Populate count variables and sort them out as we go */
- /* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = table.get_length ();
- if (unlikely (num_advances * 4 > len))
- num_advances = len / 4;
- num_metrics = num_advances + (len - 4 * num_advances) / 2;
+ if (len & 1)
+ len--;
+
+ num_long_metrics = T::is_horizontal ?
+ face->table.hhea->numberOfLongMetrics :
+#ifndef HB_NO_VERTICAL
+ face->table.vhea->numberOfLongMetrics
+#else
+ 0
+#endif
+ ;
+ if (unlikely (num_long_metrics * 4 > len))
+ num_long_metrics = len / 4;
+ len -= num_long_metrics * 4;
- /* We MUST set num_metrics to zero if num_advances is zero.
+ num_bearings = face->table.maxp->get_num_glyphs ();
+
+ if (unlikely (num_bearings < num_long_metrics))
+ num_bearings = num_long_metrics;
+ if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
+ num_bearings = num_long_metrics + len / 2;
+ len -= (num_bearings - num_long_metrics) * 2;
+
+ /* We MUST set num_bearings to zero if num_long_metrics is zero.
* Our get_advance() depends on that. */
- if (unlikely (!num_advances))
- {
- num_metrics = num_advances = 0;
- table.destroy ();
- table = hb_blob_get_empty ();
- }
+ if (unlikely (!num_long_metrics))
+ num_bearings = num_long_metrics = 0;
- var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+ num_advances = num_bearings + len / 2;
+ num_glyphs = face->get_num_glyphs ();
+ if (num_glyphs < num_advances)
+ num_glyphs = num_advances;
}
-
- void fini ()
+ ~accelerator_t ()
{
table.destroy ();
var_table.destroy ();
}
- int get_side_bearing (hb_codepoint_t glyph) const
+ bool has_data () const { return (bool) num_bearings; }
+
+ bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
+ int *lsb) const
{
- if (glyph < num_advances)
- return table->longMetricZ[glyph].sb;
+ if (glyph < num_long_metrics)
+ {
+ *lsb = table->longMetricZ[glyph].sb;
+ return true;
+ }
- if (unlikely (glyph >= num_metrics))
- return 0;
+ if (unlikely (glyph >= num_bearings))
+ return false;
- const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
- return bearings[glyph - num_advances];
+ const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+ *lsb = bearings[glyph - num_long_metrics];
+ return true;
}
- int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+ bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
+ hb_codepoint_t glyph,
+ int *lsb) const
{
- int side_bearing = get_side_bearing (glyph);
+ if (!font->num_coords)
+ return get_leading_bearing_without_var_unscaled (glyph, lsb);
#ifndef HB_NO_VAR
- if (unlikely (glyph >= num_metrics) || !font->num_coords)
- 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?!
+ float delta;
+ if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
+ get_leading_bearing_without_var_unscaled (glyph, lsb))
+ {
+ *lsb += roundf (delta);
+ return true;
+ }
- return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+ return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
#else
- return side_bearing;
+ return false;
#endif
}
- unsigned int get_advance (hb_codepoint_t glyph) const
+ unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
{
- if (unlikely (glyph >= num_metrics))
- {
- /* If num_metrics is zero, it means we don't have the metrics table
- * for this direction: return default advance. Otherwise, it means that the
- * glyph index is out of bound: return zero. */
- if (num_metrics)
- return 0;
- else
- return default_advance;
- }
+ /* OpenType case. */
+ if (glyph < num_bearings)
+ return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
- return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
+ /* If num_advances is zero, it means we don't have the metrics table
+ * for this direction: return default advance. Otherwise, there's a
+ * well-defined answer. */
+ if (unlikely (!num_advances))
+ return default_advance;
+
+#ifdef HB_NO_BEYOND_64K
+ return 0;
+#endif
+
+ if (unlikely (glyph >= num_glyphs))
+ return 0;
+
+ /* num_bearings <= glyph < num_glyphs;
+ * num_bearings <= num_advances */
+
+ /* TODO Optimize */
+
+ if (num_bearings == num_advances)
+ return get_advance_without_var_unscaled (num_bearings - 1);
+
+ const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+ const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
+
+ return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
}
- unsigned int get_advance (hb_codepoint_t glyph,
- hb_font_t *font) const
+ unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph,
+ hb_font_t *font,
+ VariationStore::cache_t *store_cache = nullptr) const
{
- unsigned int advance = get_advance (glyph);
+ unsigned int advance = get_advance_without_var_unscaled (glyph);
#ifndef HB_NO_VAR
- if (unlikely (glyph >= num_metrics) || !font->num_coords)
+ if (unlikely (glyph >= num_bearings) || !font->num_coords)
return advance;
if (var_table.get_length ())
- return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
+ return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
+ font->coords, font->num_coords,
+ store_cache)); // TODO Optimize?!
- return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+ return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
#else
return advance;
#endif
}
- unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
- {
- unsigned int num_advances = plan->num_output_glyphs ();
- unsigned int last_advance = _advance_for_new_gid (plan,
- num_advances - 1);
- while (num_advances > 1 &&
- last_advance == _advance_for_new_gid (plan,
- num_advances - 2))
- {
- num_advances--;
- }
-
- return num_advances;
- }
-
- private:
- unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
- hb_codepoint_t new_gid) const
- {
- hb_codepoint_t old_gid;
- if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
- return 0;
-
- return get_advance (old_gid);
- }
-
protected:
- unsigned int num_metrics;
- unsigned int num_advances;
+ // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
+ unsigned num_long_metrics;
+ unsigned num_bearings;
+ unsigned num_advances;
+ unsigned num_glyphs;
+
unsigned int default_advance;
- private:
+ public:
hb_blob_ptr_t<hmtxvmtx> table;
- hb_blob_ptr_t<HVARVVAR> var_table;
+ hb_blob_ptr_t<V> var_table;
};
+ /* get advance: when no variations, call get_advance_without_var_unscaled.
+ * when there're variations, get advance value from mtx_map in subset_plan*/
+ unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map,
+ unsigned new_gid,
+ const accelerator_t &_mtx) const
+ {
+ if (mtx_map->is_empty () ||
+ (new_gid == 0 && !mtx_map->has (new_gid)))
+ {
+ hb_codepoint_t old_gid = 0;
+ return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
+ _mtx.get_advance_without_var_unscaled (old_gid) : 0;
+ }
+ else
+ { return mtx_map->get (new_gid).first; }
+ }
+
protected:
UnsizedArrayOf<LongMetric>
longMetricZ; /* Paired advance width and leading
@@ -316,23 +379,29 @@ struct hmtxvmtx
* the end. This allows a monospaced
* font to vary the side bearing
* values for each glyph. */
+/*UnsizedArrayOf<UFWORD>advancesX;*/
+ /* TODO Document. */
public:
DEFINE_SIZE_ARRAY (0, longMetricZ);
};
-struct hmtx : hmtxvmtx<hmtx, hhea> {
+struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
static constexpr bool is_horizontal = true;
};
-struct vmtx : hmtxvmtx<vmtx, vhea> {
+struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
static constexpr bool is_horizontal = false;
};
-struct hmtx_accelerator_t : hmtx::accelerator_t {};
-struct vmtx_accelerator_t : vmtx::accelerator_t {};
+struct hmtx_accelerator_t : hmtx::accelerator_t {
+ hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {}
+};
+struct vmtx_accelerator_t : vmtx::accelerator_t {
+ vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index eb4c3b46e..8179e5acd 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -41,12 +41,15 @@ namespace OT {
struct BaseCoordFormat1
{
- hb_position_t get_coord () const { return coordinate; }
+ hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
+ {
+ return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -58,10 +61,10 @@ struct BaseCoordFormat1
struct BaseCoordFormat2
{
- hb_position_t get_coord () const
+ hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
{
/* TODO */
- return coordinate;
+ return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -87,9 +90,10 @@ struct BaseCoordFormat3
hb_direction_t direction) const
{
const Device &device = this+deviceTable;
- return coordinate + (HB_DIRECTION_IS_VERTICAL (direction) ?
- device.get_y_delta (font, var_store) :
- device.get_x_delta (font, var_store));
+
+ return HB_DIRECTION_IS_HORIZONTAL (direction)
+ ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
+ : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
}
@@ -120,8 +124,8 @@ struct BaseCoord
hb_direction_t direction) const
{
switch (u.format) {
- case 1: return u.format1.get_coord ();
- case 2: return u.format2.get_coord ();
+ case 1: return u.format1.get_coord (font, direction);
+ case 2: return u.format2.get_coord (font, direction);
case 3: return u.format3.get_coord (font, var_store, direction);
default:return 0;
}
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 5d98278be..0f424f5aa 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -35,9 +35,17 @@
#include "hb-set.hh"
#include "hb-bimap.hh"
+#include "OT/Layout/Common/Coverage.hh"
+#include "OT/Layout/types.hh"
+
+// TODO(garretrieger): cleanup these after migration.
+using OT::Layout::Common::Coverage;
+using OT::Layout::Common::RangeRecord;
+using OT::Layout::SmallTypes;
+using OT::Layout::MediumTypes;
#ifndef HB_MAX_NESTING_LEVEL
-#define HB_MAX_NESTING_LEVEL 6
+#define HB_MAX_NESTING_LEVEL 64
#endif
#ifndef HB_MAX_CONTEXT_LENGTH
#define HB_MAX_CONTEXT_LENGTH 64
@@ -46,10 +54,10 @@
/*
* The maximum number of times a lookup can be applied during shaping.
* Used to limit the number of iterations of the closure algorithm.
- * This must be larger than the number of times add_pause() is
+ * This must be larger than the number of times add_gsub_pause() is
* called in a collect_features call of any shaper.
*/
-#define HB_CLOSURE_MAX_STAGES 32
+#define HB_CLOSURE_MAX_STAGES 12
#endif
#ifndef HB_MAX_SCRIPTS
@@ -60,92 +68,76 @@
#define HB_MAX_LANGSYS 2000
#endif
-#ifndef HB_MAX_FEATURES
-#define HB_MAX_FEATURES 750
+#ifndef HB_MAX_LANGSYS_FEATURE_COUNT
+#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
#endif
#ifndef HB_MAX_FEATURE_INDICES
#define HB_MAX_FEATURE_INDICES 1500
#endif
-#ifndef HB_MAX_LOOKUP_INDICES
-#define HB_MAX_LOOKUP_INDICES 20000
+#ifndef HB_MAX_LOOKUP_VISIT_COUNT
+#define HB_MAX_LOOKUP_VISIT_COUNT 35000
#endif
namespace OT {
-
-#define NOT_COVERED ((unsigned int) -1)
-
-
-template<typename Iterator>
-static inline void Coverage_serialize (hb_serialize_context_t *c,
- Iterator it);
-
template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool 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 bool 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_collect_feature_substitutes_with_var_context_t
+{
+ const hb_map_t *axes_index_tag_map;
+ const hb_hashmap_t<hb_tag_t, int> *axes_location;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
+ hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+
+ // not stored in subset_plan
+ hb_set_t *feature_indices;
+ bool apply;
+ unsigned cur_record_idx;
+ hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
+};
struct hb_prune_langsys_context_t
{
hb_prune_langsys_context_t (const void *table_,
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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_),
script_langsys_map (script_langsys_map_),
duplicate_feature_map (duplicate_feature_map_),
new_feature_indexes (new_collected_feature_indexes_),
- script_count (0),langsys_count (0) {}
+ script_count (0),langsys_feature_count (0) {}
- bool visitedScript (const void *s)
- {
- if (script_count++ > HB_MAX_SCRIPTS)
- return true;
-
- return visited (s, visited_script);
- }
-
- bool visitedLangsys (const void *l)
- {
- if (langsys_count++ > HB_MAX_LANGSYS)
- return true;
-
- return visited (l, visited_langsys);
- }
+ bool visitScript ()
+ { return script_count++ < HB_MAX_SCRIPTS; }
- private:
- template <typename T>
- bool visited (const T *p, hb_set_t &visited_set)
+ bool visitLangsys (unsigned feature_count)
{
- hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
- if (visited_set.has (delta))
- return true;
-
- visited_set.add (delta);
- return false;
+ langsys_feature_count += feature_count;
+ return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT;
}
public:
const void *table;
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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;
private:
- hb_set_t visited_script;
- hb_set_t visited_langsys;
unsigned script_count;
- unsigned langsys_count;
+ unsigned langsys_feature_count;
};
struct hb_subset_layout_context_t :
@@ -173,32 +165,48 @@ struct hb_subset_layout_context_t :
bool visitLookupIndex()
{
lookup_index_count++;
- return lookup_index_count < HB_MAX_LOOKUP_INDICES;
+ return lookup_index_count < HB_MAX_LOOKUP_VISIT_COUNT;
}
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 *, (unsigned)-1, nullptr> *script_langsys_map;
+ const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
const hb_map_t *feature_index_map;
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+
unsigned cur_script_index;
+ unsigned cur_feature_var_record_idx;
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 *, (unsigned)-1, nullptr> *script_langsys_map_,
- hb_map_t *feature_index_map_) :
+ hb_tag_t tag_) :
subset_context (c_),
table_tag (tag_),
- lookup_index_map (lookup_map_),
- script_langsys_map (script_langsys_map_),
- feature_index_map (feature_index_map_),
cur_script_index (0xFFFFu),
+ cur_feature_var_record_idx (0u),
script_count (0),
langsys_count (0),
feature_index_count (0),
lookup_index_count (0)
- {}
+ {
+ if (tag_ == HB_OT_TAG_GSUB)
+ {
+ lookup_index_map = c_->plan->gsub_lookups;
+ script_langsys_map = c_->plan->gsub_langsys;
+ feature_index_map = c_->plan->gsub_features;
+ feature_substitutes_map = c_->plan->gsub_feature_substitutes_map;
+ feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map;
+ }
+ else
+ {
+ lookup_index_map = c_->plan->gpos_lookups;
+ script_langsys_map = c_->plan->gpos_langsys;
+ feature_index_map = c_->plan->gpos_features;
+ feature_substitutes_map = c_->plan->gpos_feature_substitutes_map;
+ feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map;
+ }
+ }
private:
unsigned script_count;
@@ -207,6 +215,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count;
};
+struct VariationStore;
struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{
@@ -215,15 +224,27 @@ struct hb_collect_variation_indices_context_t :
static return_t default_return_value () { return hb_empty_t (); }
hb_set_t *layout_variation_indices;
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map;
+ hb_font_t *font;
+ const VariationStore *var_store;
const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups;
+ float *store_cache;
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_,
+ hb_font_t *font_,
+ const VariationStore *var_store_,
const hb_set_t *glyph_set_,
- const hb_map_t *gpos_lookups_) :
+ const hb_map_t *gpos_lookups_,
+ float *store_cache_) :
layout_variation_indices (layout_variation_indices_),
+ varidx_delta_map (varidx_delta_map_),
+ font (font_),
+ var_store (var_store_),
glyph_set (glyph_set_),
- gpos_lookups (gpos_lookups_) {}
+ gpos_lookups (gpos_lookups_),
+ store_cache (store_cache_) {}
};
template<typename OutputArray>
@@ -332,6 +353,31 @@ struct subset_record_array_t
const void *base;
};
+template<typename OutputArray, typename Arg>
+struct subset_record_array_arg_t
+{
+ subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+ const void *base_,
+ Arg &&arg_) : subset_layout_context (c_),
+ out (out_), base (base_), arg (arg_) {}
+
+ template <typename T>
+ void
+ operator () (T&& record)
+ {
+ auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+ bool ret = record.subset (subset_layout_context, base, arg);
+ if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
+ else out->len++;
+ }
+
+ private:
+ hb_subset_layout_context_t *subset_layout_context;
+ OutputArray *out;
+ const void *base;
+ Arg &&arg;
+};
+
/*
* Helper to subset a RecordList/record array. Subsets each Record in the array and
* discards the record if the subset operation returns false.
@@ -343,6 +389,13 @@ struct
operator () (hb_subset_layout_context_t *c, OutputArray* out,
const void *base) const
{ return subset_record_array_t<OutputArray> (c, out, base); }
+
+ /* Variant with one extra argument passed to subset */
+ template<typename OutputArray, typename Arg>
+ subset_record_array_arg_t<OutputArray, Arg>
+ operator () (hb_subset_layout_context_t *c, OutputArray* out,
+ const void *base, Arg &&arg) const
+ { return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
}
HB_FUNCOBJ (subset_record_array);
@@ -394,166 +447,6 @@ HB_FUNCOBJ (serialize_math_record_array);
* Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
*/
-struct Record_sanitize_closure_t {
- hb_tag_t tag;
- const void *list_base;
-};
-
-template <typename Type>
-struct Record
-{
- int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
- bool subset (hb_subset_layout_context_t *c, const void *base) const
- {
- TRACE_SUBSET (this);
- auto *out = c->subset_context->serializer->embed (this);
- if (unlikely (!out)) return_trace (false);
- bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
- {
- TRACE_SANITIZE (this);
- const Record_sanitize_closure_t closure = {tag, base};
- return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
- }
-
- Tag tag; /* 4-byte Tag identifier */
- Offset16To<Type>
- offset; /* Offset from beginning of object holding
- * the Record */
- public:
- DEFINE_SIZE_STATIC (6);
-};
-
-template <typename Type>
-struct RecordArrayOf : SortedArray16Of<Record<Type>>
-{
- const Offset16To<Type>& get_offset (unsigned int i) const
- { return (*this)[i].offset; }
- Offset16To<Type>& get_offset (unsigned int i)
- { return (*this)[i].offset; }
- const Tag& get_tag (unsigned int i) const
- { return (*this)[i].tag; }
- unsigned int get_tags (unsigned int start_offset,
- unsigned int *record_count /* IN/OUT */,
- hb_tag_t *record_tags /* OUT */) const
- {
- if (record_count)
- {
- + this->sub_array (start_offset, record_count)
- | hb_map (&Record<Type>::tag)
- | hb_sink (hb_array (record_tags, *record_count))
- ;
- }
- return this->len;
- }
- bool find_index (hb_tag_t tag, unsigned int *index) const
- {
- return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
- }
-};
-
-template <typename Type>
-struct RecordListOf : RecordArrayOf<Type>
-{
- const Type& operator [] (unsigned int i) const
- { return this+this->get_offset (i); }
-
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- + this->iter ()
- | hb_apply (subset_record_array (l, out, this))
- ;
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (RecordArrayOf<Type>::sanitize (c, this));
- }
-};
-
-struct Feature;
-
-struct RecordListOfFeature : RecordListOf<Feature>
-{
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
- unsigned count = this->len;
- + hb_zip (*this, hb_range (count))
- | hb_filter (l->feature_index_map, hb_second)
- | hb_map (hb_first)
- | hb_apply (subset_record_array (l, out, this))
- ;
- return_trace (true);
- }
-};
-
-struct Script;
-struct RecordListOfScript : RecordListOf<Script>
-{
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
- unsigned count = this->len;
- for (auto _ : + hb_zip (*this, hb_range (count)))
- {
- auto snap = c->serializer->snapshot ();
- l->cur_script_index = _.second;
- bool ret = _.first.subset (l, this);
- if (!ret) c->serializer->revert (snap);
- else out->len++;
- }
-
- return_trace (true);
- }
-};
-
-struct RangeRecord
-{
- int cmp (hb_codepoint_t g) const
- { return g < first ? -1 : g <= last ? 0 : +1; }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this));
- }
-
- bool intersects (const hb_set_t *glyphs) const
- { return glyphs->intersects (first, last); }
-
- template <typename set_t>
- bool collect_coverage (set_t *glyphs) const
- { return glyphs->add_range (first, last); }
-
- HBGlyphID16 first; /* First GlyphID in the range */
- HBGlyphID16 last; /* Last GlyphID in the range */
- HBUINT16 value; /* Value */
- public:
- DEFINE_SIZE_STATIC (6);
-};
-DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
-
-
struct IndexArray : Array16Of<Index>
{
bool intersects (const hb_map_t *indexes) const
@@ -585,7 +478,7 @@ struct IndexArray : Array16Of<Index>
{
if (_count)
{
- + this->sub_array (start_offset, _count)
+ + this->as_array ().sub_array (start_offset, _count)
| hb_sink (hb_array (_indexes, *_count))
;
}
@@ -599,243 +492,6 @@ struct IndexArray : Array16Of<Index>
};
-struct LangSys
-{
- unsigned int get_feature_count () const
- { return featureIndex.len; }
- hb_tag_t get_feature_index (unsigned int i) const
- { return featureIndex[i]; }
- unsigned int get_feature_indexes (unsigned int start_offset,
- unsigned int *feature_count /* IN/OUT */,
- unsigned int *feature_indexes /* OUT */) const
- { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
- void add_feature_indexes_to (hb_set_t *feature_indexes) const
- { featureIndex.add_indexes_to (feature_indexes); }
-
- bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
- unsigned int get_required_feature_index () const
- {
- if (reqFeatureIndex == 0xFFFFu)
- return Index::NOT_FOUND_INDEX;
- return reqFeatureIndex;
- }
-
- LangSys* copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- return_trace (c->embed (*this));
- }
-
- bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
- {
- if (reqFeatureIndex != o.reqFeatureIndex)
- return false;
-
- auto iter =
- + hb_iter (featureIndex)
- | hb_filter (feature_index_map)
- | hb_map (feature_index_map)
- ;
-
- auto o_iter =
- + hb_iter (o.featureIndex)
- | hb_filter (feature_index_map)
- | hb_map (feature_index_map)
- ;
-
- if (iter.len () != o_iter.len ())
- return false;
-
- for (const auto _ : + hb_zip (iter, o_iter))
- if (_.first != _.second) return false;
-
- return true;
- }
-
- void collect_features (hb_prune_langsys_context_t *c) const
- {
- if (!has_required_feature () && !get_feature_count ()) return;
- if (c->visitedLangsys (this)) return;
- if (has_required_feature () &&
- c->duplicate_feature_map->has (reqFeatureIndex))
- c->new_feature_indexes->add (get_required_feature_index ());
-
- + hb_iter (featureIndex)
- | hb_filter (c->duplicate_feature_map)
- | hb_sink (c->new_feature_indexes)
- ;
- }
-
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l,
- const Tag *tag = nullptr) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
- out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
-
- if (!l->visitFeatureIndex (featureIndex.len))
- return_trace (false);
-
- auto it =
- + hb_iter (featureIndex)
- | hb_filter (l->feature_index_map)
- | hb_map (l->feature_index_map)
- ;
-
- bool ret = bool (it);
- out->featureIndex.serialize (c->serializer, l, it);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c,
- const Record_sanitize_closure_t * = nullptr) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && featureIndex.sanitize (c));
- }
-
- Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
- * reordering table) */
- HBUINT16 reqFeatureIndex;/* Index of a feature required for this
- * language system--if no required features
- * = 0xFFFFu */
- IndexArray featureIndex; /* Array of indices into the FeatureList */
- public:
- DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
-};
-DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
-
-struct Script
-{
- unsigned int get_lang_sys_count () const
- { return langSys.len; }
- const Tag& get_lang_sys_tag (unsigned int i) const
- { return langSys.get_tag (i); }
- unsigned int get_lang_sys_tags (unsigned int start_offset,
- unsigned int *lang_sys_count /* IN/OUT */,
- hb_tag_t *lang_sys_tags /* OUT */) const
- { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
- const LangSys& get_lang_sys (unsigned int i) const
- {
- if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
- return this+langSys[i].offset;
- }
- bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
- { return langSys.find_index (tag, index); }
-
- bool has_default_lang_sys () const { return defaultLangSys != 0; }
- const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
-
- void prune_langsys (hb_prune_langsys_context_t *c,
- unsigned script_index) const
- {
- if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
- if (c->visitedScript (this)) return;
-
- 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);
- return;
- }
- }
-
- unsigned langsys_count = get_lang_sys_count ();
- if (has_default_lang_sys ())
- {
- //only collect features from non-redundant langsys
- const LangSys& d = get_default_lang_sys ();
- d.collect_features (c);
-
- for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
- {
- const LangSys& l = this+_.first.offset;
- if (l.compare (d, c->duplicate_feature_map)) continue;
-
- l.collect_features (c);
- c->script_langsys_map->get (script_index)->add (_.second);
- }
- }
- else
- {
- for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
- {
- const LangSys& l = this+_.first.offset;
- l.collect_features (c);
- c->script_langsys_map->get (script_index)->add (_.second);
- }
- }
- }
-
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l,
- const Tag *tag) const
- {
- TRACE_SUBSET (this);
- if (!l->visitScript ()) return_trace (false);
-
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
- bool defaultLang = false;
- if (has_default_lang_sys ())
- {
- c->serializer->push ();
- const LangSys& ls = this+defaultLangSys;
- bool ret = ls.subset (c, l);
- if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
- {
- c->serializer->pop_discard ();
- out->defaultLangSys = 0;
- }
- else
- {
- c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
- defaultLang = true;
- }
- }
-
- const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
- if (active_langsys)
- {
- unsigned count = langSys.len;
- + hb_zip (langSys, hb_range (count))
- | hb_filter (active_langsys, hb_second)
- | hb_map (hb_first)
- | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
- | hb_apply (subset_record_array (l, &(out->langSys), this))
- ;
- }
-
- return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
- }
-
- bool sanitize (hb_sanitize_context_t *c,
- const Record_sanitize_closure_t * = nullptr) const
- {
- TRACE_SANITIZE (this);
- return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
- }
-
- protected:
- Offset16To<LangSys>
- defaultLangSys; /* Offset to DefaultLangSys table--from
- * beginning of Script table--may be Null */
- RecordArrayOf<LangSys>
- langSys; /* Array of LangSysRecords--listed
- * alphabetically by LangSysTag */
- public:
- DEFINE_SIZE_ARRAY_SIZED (4, langSys);
-};
-
-typedef RecordListOfScript ScriptList;
-
-
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
struct FeatureParamsSize
{
@@ -845,7 +501,7 @@ struct FeatureParamsSize
if (unlikely (!c->check_struct (this))) return_trace (false);
/* This subtable has some "history", if you will. Some earlier versions of
- * Adobe tools calculated the offset of the FeatureParams sutable from the
+ * Adobe tools calculated the offset of the FeatureParams subtable from the
* beginning of the FeatureList table! Now, that is dealt with in the
* Feature implementation. But we still need to be able to tell junk from
* real data. Note: We don't check that the nameID actually exists.
@@ -1002,7 +658,7 @@ struct FeatureParamsCharacterVariants
{
if (char_count)
{
- + characters.sub_array (start_offset, char_count)
+ + characters.as_array ().sub_array (start_offset, char_count)
| hb_sink (hb_array (chars, *char_count))
;
}
@@ -1118,6 +774,11 @@ struct FeatureParams
DEFINE_SIZE_MIN (0);
};
+struct Record_sanitize_closure_t {
+ hb_tag_t tag;
+ const void *list_base;
+};
+
struct Feature
{
unsigned int get_lookup_count () const
@@ -1213,9 +874,395 @@ struct Feature
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
};
+template <typename Type>
+struct Record
+{
+ int cmp (hb_tag_t a) const { return tag.cmp (a); }
+
+ bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->subset_context->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (!f_sub)
+ return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
+
+ const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
+ auto *s = c->subset_context->serializer;
+ s->push ();
+
+ out->offset = 0;
+ bool ret = f.subset (c->subset_context, c, &tag);
+ if (ret)
+ s->add_link (out->offset, s->pop_pack ());
+ else
+ s->pop_discard ();
+
+ return_trace (ret);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ const Record_sanitize_closure_t closure = {tag, base};
+ return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+ }
+
+ Tag tag; /* 4-byte Tag identifier */
+ Offset16To<Type>
+ offset; /* Offset from beginning of object holding
+ * the Record */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
+{
+ const Offset16To<Type>& get_offset (unsigned int i) const
+ { return (*this)[i].offset; }
+ Offset16To<Type>& get_offset (unsigned int i)
+ { return (*this)[i].offset; }
+ const Tag& get_tag (unsigned int i) const
+ { return (*this)[i].tag; }
+ unsigned int get_tags (unsigned int start_offset,
+ unsigned int *record_count /* IN/OUT */,
+ hb_tag_t *record_tags /* OUT */) const
+ {
+ if (record_count)
+ {
+ + this->as_array ().sub_array (start_offset, record_count)
+ | hb_map (&Record<Type>::tag)
+ | hb_sink (hb_array (record_tags, *record_count))
+ ;
+ }
+ return this->len;
+ }
+ bool find_index (hb_tag_t tag, unsigned int *index) const
+ {
+ return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+ }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+ const Type& operator [] (unsigned int i) const
+ { return this+this->get_offset (i); }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ + this->iter ()
+ | hb_apply (subset_record_array (l, out, this))
+ ;
+ return_trace (true);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (RecordArrayOf<Type>::sanitize (c, this));
+ }
+};
+
+struct RecordListOfFeature : RecordListOf<Feature>
+{
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ + hb_enumerate (*this)
+ | hb_filter (l->feature_index_map, hb_first)
+ | hb_apply ([l, out, this] (const hb_pair_t<unsigned, const Record<Feature>&>& _)
+ {
+ const Feature *f_sub = nullptr;
+ const Feature **f = nullptr;
+ if (l->feature_substitutes_map->has (_.first, &f))
+ f_sub = *f;
+
+ subset_record_array (l, out, this, f_sub) (_.second);
+ })
+ ;
+
+ return_trace (true);
+ }
+};
+
typedef RecordListOf<Feature> FeatureList;
+struct LangSys
+{
+ unsigned int get_feature_count () const
+ { return featureIndex.len; }
+ hb_tag_t get_feature_index (unsigned int i) const
+ { return featureIndex[i]; }
+ unsigned int get_feature_indexes (unsigned int start_offset,
+ unsigned int *feature_count /* IN/OUT */,
+ unsigned int *feature_indexes /* OUT */) const
+ { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
+ void add_feature_indexes_to (hb_set_t *feature_indexes) const
+ { featureIndex.add_indexes_to (feature_indexes); }
+
+ bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
+ unsigned int get_required_feature_index () const
+ {
+ if (reqFeatureIndex == 0xFFFFu)
+ return Index::NOT_FOUND_INDEX;
+ return reqFeatureIndex;
+ }
+
+ LangSys* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (c->embed (*this));
+ }
+
+ bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
+ {
+ if (reqFeatureIndex != o.reqFeatureIndex)
+ return false;
+
+ auto iter =
+ + hb_iter (featureIndex)
+ | hb_filter (feature_index_map)
+ | hb_map (feature_index_map)
+ ;
+
+ auto o_iter =
+ + hb_iter (o.featureIndex)
+ | hb_filter (feature_index_map)
+ | hb_map (feature_index_map)
+ ;
+
+ for (; iter && o_iter; iter++, o_iter++)
+ {
+ unsigned a = *iter;
+ unsigned b = *o_iter;
+ if (a != b) return false;
+ }
+
+ if (iter || o_iter) return false;
+
+ return true;
+ }
+
+ void collect_features (hb_prune_langsys_context_t *c) const
+ {
+ if (!has_required_feature () && !get_feature_count ()) return;
+ if (has_required_feature () &&
+ c->duplicate_feature_map->has (reqFeatureIndex))
+ c->new_feature_indexes->add (get_required_feature_index ());
+
+ + hb_iter (featureIndex)
+ | hb_filter (c->duplicate_feature_map)
+ | hb_sink (c->new_feature_indexes)
+ ;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l,
+ const Tag *tag = nullptr) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ const uint32_t *v;
+ out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
+
+ if (!l->visitFeatureIndex (featureIndex.len))
+ return_trace (false);
+
+ auto it =
+ + hb_iter (featureIndex)
+ | hb_filter (l->feature_index_map)
+ | hb_map (l->feature_index_map)
+ ;
+
+ bool ret = bool (it);
+ out->featureIndex.serialize (c->serializer, l, it);
+ return_trace (ret);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c,
+ const Record_sanitize_closure_t * = nullptr) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && featureIndex.sanitize (c));
+ }
+
+ Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
+ * reordering table) */
+ HBUINT16 reqFeatureIndex;/* Index of a feature required for this
+ * language system--if no required features
+ * = 0xFFFFu */
+ IndexArray featureIndex; /* Array of indices into the FeatureList */
+ public:
+ DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
+};
+DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
+
+struct Script
+{
+ unsigned int get_lang_sys_count () const
+ { return langSys.len; }
+ const Tag& get_lang_sys_tag (unsigned int i) const
+ { return langSys.get_tag (i); }
+ unsigned int get_lang_sys_tags (unsigned int start_offset,
+ unsigned int *lang_sys_count /* IN/OUT */,
+ hb_tag_t *lang_sys_tags /* OUT */) const
+ { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
+ const LangSys& get_lang_sys (unsigned int i) const
+ {
+ if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+ return this+langSys[i].offset;
+ }
+ bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+ { return langSys.find_index (tag, index); }
+
+ bool has_default_lang_sys () const { return defaultLangSys != 0; }
+ const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
+
+ void prune_langsys (hb_prune_langsys_context_t *c,
+ unsigned script_index) const
+ {
+ if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
+ if (!c->visitScript ()) return;
+
+ if (!c->script_langsys_map->has (script_index))
+ {
+ if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
+ return;
+ }
+
+ if (has_default_lang_sys ())
+ {
+ //only collect features from non-redundant langsys
+ const LangSys& d = get_default_lang_sys ();
+ if (c->visitLangsys (d.get_feature_count ())) {
+ d.collect_features (c);
+ }
+
+ for (auto _ : + hb_enumerate (langSys))
+ {
+ const LangSys& l = this+_.second.offset;
+ if (!c->visitLangsys (l.get_feature_count ())) continue;
+ if (l.compare (d, c->duplicate_feature_map)) continue;
+
+ l.collect_features (c);
+ c->script_langsys_map->get (script_index)->add (_.first);
+ }
+ }
+ else
+ {
+ for (auto _ : + hb_enumerate (langSys))
+ {
+ const LangSys& l = this+_.second.offset;
+ if (!c->visitLangsys (l.get_feature_count ())) continue;
+ l.collect_features (c);
+ c->script_langsys_map->get (script_index)->add (_.first);
+ }
+ }
+ }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l,
+ const Tag *tag) const
+ {
+ TRACE_SUBSET (this);
+ if (!l->visitScript ()) return_trace (false);
+ if (tag && !c->plan->layout_scripts->has (*tag))
+ return false;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ bool defaultLang = false;
+ if (has_default_lang_sys ())
+ {
+ c->serializer->push ();
+ const LangSys& ls = this+defaultLangSys;
+ bool ret = ls.subset (c, l);
+ if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
+ {
+ c->serializer->pop_discard ();
+ out->defaultLangSys = 0;
+ }
+ else
+ {
+ c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
+ defaultLang = true;
+ }
+ }
+
+ const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
+ if (active_langsys)
+ {
+ + hb_enumerate (langSys)
+ | hb_filter (active_langsys, hb_first)
+ | hb_map (hb_second)
+ | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
+ | hb_apply (subset_record_array (l, &(out->langSys), this))
+ ;
+ }
+
+ return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c,
+ const Record_sanitize_closure_t * = nullptr) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
+ }
+
+ protected:
+ Offset16To<LangSys>
+ defaultLangSys; /* Offset to DefaultLangSys table--from
+ * beginning of Script table--may be Null */
+ RecordArrayOf<LangSys>
+ langSys; /* Array of LangSysRecords--listed
+ * alphabetically by LangSysTag */
+ public:
+ DEFINE_SIZE_ARRAY_SIZED (4, langSys);
+};
+
+struct RecordListOfScript : RecordListOf<Script>
+{
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ for (auto _ : + hb_enumerate (*this))
+ {
+ auto snap = c->serializer->snapshot ();
+ l->cur_script_index = _.first;
+ bool ret = _.second.subset (l, this);
+ if (!ret) c->serializer->revert (snap);
+ else out->len++;
+ }
+
+ return_trace (true);
+ }
+};
+
+typedef RecordListOfScript ScriptList;
+
+
+
struct LookupFlag : HBUINT16
{
enum Flags {
@@ -1336,7 +1383,13 @@ struct Lookup
outMarkFilteringSet = markFilteringSet;
}
- return_trace (out->subTable.len);
+ // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
+ // indices being consistent with those computed during planning. So if an empty lookup is
+ // discarded during the subset phase it will invalidate all subsequent lookup indices.
+ // Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning
+ // phase, but it can happen in rare cases such as when during closure subtable is considered
+ // degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
+ return true;
}
template <typename TSubTable>
@@ -1377,7 +1430,7 @@ struct Lookup
return_trace (true);
}
- private:
+ protected:
HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
HBUINT16 lookupFlag; /* Lookup qualifiers */
Array16Of<Offset16>
@@ -1389,10 +1442,11 @@ struct Lookup
DEFINE_SIZE_ARRAY (6, subTable);
};
-typedef List16OfOffset16To<Lookup> LookupList;
+template <typename Types>
+using LookupList = List16OfOffsetTo<Lookup, typename Types::HBUINT>;
-template <typename TLookup>
-struct LookupOffsetList : List16OfOffset16To<TLookup>
+template <typename TLookup, typename OffsetType>
+struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
{
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
@@ -1401,10 +1455,9 @@ struct LookupOffsetList : List16OfOffset16To<TLookup>
auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- unsigned count = this->len;
- + hb_zip (*this, hb_range (count))
- | hb_filter (l->lookup_index_map, hb_second)
- | hb_map (hb_first)
+ + hb_enumerate (*this)
+ | hb_filter (l->lookup_index_map, hb_first)
+ | hb_map (hb_second)
| hb_apply (subset_offset_array (c, *out, this))
;
return_trace (true);
@@ -1422,464 +1475,15 @@ struct LookupOffsetList : List16OfOffset16To<TLookup>
* Coverage Table
*/
-struct CoverageFormat1
-{
- friend struct Coverage;
-
- private:
- unsigned int get_coverage (hb_codepoint_t glyph_id) const
- {
- unsigned int i;
- glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
- return i;
- }
-
- template <typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c, Iterator glyphs)
- {
- TRACE_SERIALIZE (this);
- return_trace (glyphArray.serialize (c, glyphs));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (glyphArray.sanitize (c));
- }
-
- bool intersects (const hb_set_t *glyphs) const
- {
- /* TODO Speed up, using hb_set_next() and bsearch()? */
- for (const auto& g : glyphArray.as_array ())
- if (glyphs->has (g))
- return true;
- return false;
- }
- bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
- { return glyphs->has (glyphArray[index]); }
-
- void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
- {
- unsigned count = glyphArray.len;
- for (unsigned i = 0; i < count; i++)
- if (glyphs->has (glyphArray[i]))
- intersect_glyphs->add (glyphArray[i]);
- }
-
- template <typename set_t>
- bool collect_coverage (set_t *glyphs) const
- { return glyphs->add_sorted_array (glyphArray.as_array ()); }
-
- public:
- /* Older compilers need this to be public. */
- struct iter_t
- {
- void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
- void fini () {}
- bool more () const { return i < c->glyphArray.len; }
- 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; }
-
- private:
- const struct CoverageFormat1 *c;
- unsigned int i;
- };
- private:
-
- protected:
- HBUINT16 coverageFormat; /* Format identifier--format = 1 */
- SortedArray16Of<HBGlyphID16>
- glyphArray; /* Array of GlyphIDs--in numerical order */
- public:
- DEFINE_SIZE_ARRAY (4, glyphArray);
-};
-
-struct CoverageFormat2
-{
- friend struct Coverage;
-
- private:
- unsigned int get_coverage (hb_codepoint_t glyph_id) const
- {
- const RangeRecord &range = rangeRecord.bsearch (glyph_id);
- return likely (range.first <= range.last)
- ? (unsigned int) range.value + (glyph_id - range.first)
- : NOT_COVERED;
- }
-
- template <typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c, Iterator glyphs)
- {
- 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;
- hb_codepoint_t last = (hb_codepoint_t) -2;
- for (auto g: glyphs)
- {
- if (last + 1 != g)
- num_ranges++;
- last = g;
- }
-
- if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
-
- unsigned count = 0;
- unsigned range = (unsigned) -1;
- last = (hb_codepoint_t) -2;
- for (auto g: glyphs)
- {
- if (last + 1 != g)
- {
- range++;
- rangeRecord[range].first = g;
- rangeRecord[range].value = count;
- }
- rangeRecord[range].last = g;
- last = g;
- count++;
- }
-
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (rangeRecord.sanitize (c));
- }
-
- 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;
- }
- bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
- {
- /* TODO(iter) Rewrite as dagger. */
- for (const auto& range : rangeRecord.as_array ())
- {
- 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;
- }
- return false;
- }
-
- void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
- {
- 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);
- }
- }
-
- template <typename set_t>
- bool collect_coverage (set_t *glyphs) const
- {
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
- if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
- return false;
- return true;
- }
-
- public:
- /* Older compilers need this to be public. */
- struct iter_t
- {
- void init (const CoverageFormat2 &c_)
- {
- c = &c_;
- coverage = 0;
- i = 0;
- j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
- if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
- {
- /* Broken table. Skip. */
- i = c->rangeRecord.len;
- }
- }
- void fini () {}
- bool more () const { return i < c->rangeRecord.len; }
- void next ()
- {
- if (j >= c->rangeRecord[i].last)
- {
- i++;
- if (more ())
- {
- unsigned int old = coverage;
- j = c->rangeRecord[i].first;
- coverage = c->rangeRecord[i].value;
- if (unlikely (coverage != old + 1))
- {
- /* Broken table. Skip. Important to avoid DoS.
- * Also, our callers depend on coverage being
- * consecutive and monotonically increasing,
- * ie. iota(). */
- i = c->rangeRecord.len;
- return;
- }
- }
- return;
- }
- coverage++;
- j++;
- }
- 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; }
-
- private:
- const struct CoverageFormat2 *c;
- unsigned int i, coverage;
- hb_codepoint_t j;
- };
- private:
-
- protected:
- HBUINT16 coverageFormat; /* Format identifier--format = 2 */
- SortedArray16Of<RangeRecord>
- rangeRecord; /* Array of glyph ranges--ordered by
- * Start GlyphID. rangeCount entries
- * long */
- public:
- DEFINE_SIZE_ARRAY (4, rangeRecord);
-};
-
-struct Coverage
-{
- /* Has interface. */
- static constexpr unsigned SENTINEL = NOT_COVERED;
- typedef unsigned int value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
- /* Predicate. */
- bool operator () (hb_codepoint_t k) const { return has (k); }
-
- unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
- unsigned int get_coverage (hb_codepoint_t glyph_id) const
- {
- switch (u.format) {
- case 1: return u.format1.get_coverage (glyph_id);
- case 2: return u.format2.get_coverage (glyph_id);
- default:return NOT_COVERED;
- }
- }
-
- template <typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c, Iterator glyphs)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
-
- unsigned count = 0;
- unsigned num_ranges = 0;
- hb_codepoint_t last = (hb_codepoint_t) -2;
- for (auto g: glyphs)
- {
- if (last + 1 != g)
- num_ranges++;
- last = g;
- count++;
- }
- u.format = count <= num_ranges * 3 ? 1 : 2;
-
- switch (u.format)
- {
- case 1: return_trace (u.format1.serialize (c, glyphs));
- case 2: return_trace (u.format2.serialize (c, glyphs));
- default:return_trace (false);
- }
- }
-
- 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)
- ;
-
- bool ret = bool (it);
- Coverage_serialize (c->serializer, it);
- return_trace (ret);
- }
-
- 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));
- default:return_trace (true);
- }
- }
-
- bool intersects (const hb_set_t *glyphs) const
- {
- switch (u.format)
- {
- case 1: return u.format1.intersects (glyphs);
- case 2: return u.format2.intersects (glyphs);
- default:return false;
- }
- }
- bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
- {
- switch (u.format)
- {
- case 1: return u.format1.intersects_coverage (glyphs, index);
- case 2: return u.format2.intersects_coverage (glyphs, index);
- default:return false;
- }
- }
-
- /* Might return false if array looks unsorted.
- * Used for faster rejection of corrupt data. */
- template <typename set_t>
- bool collect_coverage (set_t *glyphs) const
- {
- switch (u.format)
- {
- case 1: return u.format1.collect_coverage (glyphs);
- case 2: return u.format2.collect_coverage (glyphs);
- default:return false;
- }
- }
-
- void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
- {
- switch (u.format)
- {
- case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs);
- case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs);
- default:return ;
- }
- }
-
- struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
- {
- static constexpr bool is_sorted_iterator = true;
- iter_t (const Coverage &c_ = Null (Coverage))
- {
- memset (this, 0, sizeof (*this));
- format = c_.u.format;
- switch (format)
- {
- case 1: u.format1.init (c_.u.format1); return;
- case 2: u.format2.init (c_.u.format2); return;
- default: return;
- }
- }
- bool __more__ () const
- {
- switch (format)
- {
- case 1: return u.format1.more ();
- case 2: return u.format2.more ();
- default:return false;
- }
- }
- void __next__ ()
- {
- switch (format)
- {
- case 1: u.format1.next (); break;
- case 2: u.format2.next (); break;
- default: break;
- }
- }
- typedef hb_codepoint_t __item_t__;
- __item_t__ __item__ () const { return get_glyph (); }
-
- hb_codepoint_t get_glyph () const
- {
- switch (format)
- {
- case 1: return u.format1.get_glyph ();
- case 2: return u.format2.get_glyph ();
- default:return 0;
- }
- }
- bool operator != (const iter_t& o) const
- {
- if (format != o.format) return true;
- switch (format)
- {
- case 1: return u.format1 != o.u.format1;
- case 2: return u.format2 != o.u.format2;
- default:return false;
- }
- }
-
- private:
- unsigned int format;
- union {
- CoverageFormat2::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
- CoverageFormat1::iter_t format1;
- } u;
- };
- iter_t iter () const { return iter_t (*this); }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- CoverageFormat1 format1;
- CoverageFormat2 format2;
- } u;
- public:
- DEFINE_SIZE_UNION (2, format);
-};
-template<typename Iterator>
-static inline void
-Coverage_serialize (hb_serialize_context_t *c,
- Iterator it)
-{ 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,
+static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
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)));
- return;
- }
+ return ClassDef_serialize (c, glyph_and_klass.iter ());
/* any glyph not assigned a class value falls into Class zero (0),
* if any glyph assigned to class 0, remapping must start with 0->0*/
@@ -1887,31 +1491,30 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
klass_map->set (0, 0);
unsigned idx = klass_map->has (0) ? 1 : 0;
- for (const unsigned k: klasses.iter ())
+ for (const unsigned k: klasses)
{
if (klass_map->has (k)) continue;
klass_map->set (k, idx);
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);
+ return ClassDef_serialize (c, glyph_and_klass.iter ());
}
/*
* Class Definition Table
*/
-struct ClassDefFormat1
+template <typename Types>
+struct ClassDefFormat1_3
{
friend struct ClassDef;
@@ -1921,8 +1524,13 @@ struct ClassDefFormat1
return classValue[(unsigned int) (glyph_id - startGlyph)];
}
+ unsigned get_population () const
+ {
+ return classValue.len;
+ }
+
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
Iterator it)
{
@@ -1945,7 +1553,7 @@ struct ClassDefFormat1
startGlyph = glyph_min;
if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
- for (const hb_pair_t<hb_codepoint_t, unsigned> gid_klass_pair : + it)
+ for (const hb_pair_t<hb_codepoint_t, uint32_t> gid_klass_pair : + it)
{
unsigned idx = gid_klass_pair.first - glyph_min;
classValue[idx] = gid_klass_pair.second;
@@ -1960,36 +1568,38 @@ 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;
+ if (!ClassDef_remap_and_serialize (c->serializer,
+ orig_klasses,
+ use_class_zero,
+ glyph_and_klass,
+ klass_map))
+ return_trace (false);
+ return_trace (keep_empty_table || (bool) glyph_and_klass);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1998,6 +1608,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
{
@@ -2032,11 +1644,10 @@ struct ClassDefFormat1
bool intersects (const hb_set_t *glyphs) const
{
- /* TODO Speed up, using hb_set_next()? */
hb_codepoint_t start = startGlyph;
hb_codepoint_t end = startGlyph + classValue.len;
for (hb_codepoint_t iter = startGlyph - 1;
- hb_set_next (glyphs, &iter) && iter < end;)
+ glyphs->next (&iter) && iter < end;)
if (classValue[iter - start]) return true;
return false;
}
@@ -2047,18 +1658,17 @@ struct ClassDefFormat1
{
/* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- if (!hb_set_next (glyphs, &g)) return false;
+ if (!glyphs->next (&g)) return false;
if (g < startGlyph) return true;
g = startGlyph + count - 1;
- if (hb_set_next (glyphs, &g)) return true;
+ if (glyphs->next (&g)) return true;
/* Fall through. */
}
/* TODO Speed up, using set overlap first? */
/* TODO(iter) Rewrite as dagger. */
- HBUINT16 k {klass};
const HBUINT16 *arr = classValue.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (arr[i] == k && glyphs->has (startGlyph + i))
+ if (arr[i] == klass && glyphs->has (startGlyph + i))
return true;
return false;
}
@@ -2068,17 +1678,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 (uint32_t g = HB_SET_VALUE_INVALID;
+ glyphs->next (&g) && g < start_glyph;)
+ intersect_glyphs->add (g);
+
+ for (uint32_t g = startGlyph + count - 1;
+ glyphs-> next (&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;
+ glyphs->next (&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
@@ -2099,14 +1724,16 @@ struct ClassDefFormat1
protected:
HBUINT16 classFormat; /* Format identifier--format = 1 */
- HBGlyphID16 startGlyph; /* First GlyphID of the classValueArray */
- Array16Of<HBUINT16>
+ typename Types::HBGlyphID
+ startGlyph; /* First GlyphID of the classValueArray */
+ typename Types::template ArrayOf<HBUINT16>
classValue; /* Array of Class Values--one per GlyphID */
public:
- DEFINE_SIZE_ARRAY (6, classValue);
+ DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue);
};
-struct ClassDefFormat2
+template <typename Types>
+struct ClassDefFormat2_4
{
friend struct ClassDef;
@@ -2116,8 +1743,16 @@ struct ClassDefFormat2
return rangeRecord.bsearch (glyph_id).value;
}
+ unsigned get_population () const
+ {
+ typename Types::large_int ret = 0;
+ for (const auto &r : rangeRecord)
+ ret += r.get_population ();
+ return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+ }
+
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
Iterator it)
{
@@ -2135,12 +1770,12 @@ struct ClassDefFormat2
hb_codepoint_t prev_gid = (*it).first;
unsigned prev_klass = (*it).second;
- RangeRecord range_rec;
+ RangeRecord<Types> range_rec;
range_rec.first = prev_gid;
range_rec.last = prev_gid;
range_rec.value = prev_klass;
- RangeRecord *record = c->copy (range_rec);
+ auto *record = c->copy (range_rec);
if (unlikely (!record)) return_trace (false);
for (const auto gid_klass_pair : + (++it))
@@ -2178,37 +1813,59 @@ 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;
+ const hb_set_t &glyph_set = *c->plan->glyphset_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++)
+ if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
+ < get_population ())
{
- unsigned klass = rangeRecord[i].value;
- if (!klass) continue;
- hb_codepoint_t start = rangeRecord[i].first;
- hb_codepoint_t end = rangeRecord[i].last + 1;
- for (hb_codepoint_t g = start; g < end; g++)
+ for (hb_codepoint_t g : glyph_set)
{
- if (!glyphset.has (g)) continue;
- if (glyph_filter && !glyph_filter->has (g)) continue;
- glyphs.push (glyph_map[g]);
- gid_org_klass_map.set (glyph_map[g], klass);
+ unsigned klass = get_class (g);
+ if (!klass) 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;
+ glyph_and_klass.push (hb_pair (new_gid, klass));
orig_klasses.add (klass);
}
}
+ else
+ {
+ unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
+ for (auto &range : rangeRecord)
+ {
+ unsigned klass = range.value;
+ if (!klass) continue;
+ hb_codepoint_t start = range.first;
+ hb_codepoint_t end = hb_min (range.last + 1, num_source_glyphs);
+ for (hb_codepoint_t g = start; g < end; g++)
+ {
+ hb_codepoint_t new_gid = glyph_map[g];
+ if (new_gid == HB_MAP_VALUE_INVALID) continue;
+ if (glyph_filter && !glyph_filter->has (g)) continue;
+ 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;
+ if (!ClassDef_remap_and_serialize (c->serializer,
+ orig_klasses,
+ use_class_zero,
+ glyph_and_klass,
+ klass_map))
+ return_trace (false);
+ return_trace (keep_empty_table || (bool) glyph_and_klass);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2217,13 +1874,14 @@ 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
{
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].value)
- if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+ for (auto &range : rangeRecord)
+ if (range.value)
+ if (unlikely (!range.collect_coverage (glyphs)))
return false;
return true;
}
@@ -2231,11 +1889,10 @@ struct ClassDefFormat2
template <typename set_t>
bool collect_class (set_t *glyphs, unsigned int klass) const
{
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (rangeRecord[i].value == klass)
- if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+ if (range.value == klass)
+ if (unlikely (!range.collect_coverage (glyphs)))
return false;
}
return true;
@@ -2243,90 +1900,87 @@ struct ClassDefFormat2
bool intersects (const hb_set_t *glyphs) const
{
- /* TODO Speed up, using hb_set_next() and bsearch()? */
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
+ if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- const auto& range = rangeRecord[i];
- if (range.intersects (glyphs) && range.value)
- return true;
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ if (get_class (g))
+ return true;
+ return false;
}
- return false;
+
+ return hb_any (+ hb_iter (rangeRecord)
+ | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
}
bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
- unsigned int count = rangeRecord.len;
if (klass == 0)
{
/* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
break;
- if (g < rangeRecord[i].first)
+ if (g < range.first)
return true;
- g = rangeRecord[i].last;
+ g = range.last;
}
- if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+ if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
return true;
/* Fall through. */
}
- /* 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))
+ for (const auto &range : rangeRecord)
+ if (range.value == klass && range.intersects (*glyphs))
return true;
return false;
}
void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
{
- unsigned count = rangeRecord.len;
if (klass == 0)
{
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- 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 (!glyphs->next (&g))
+ goto done;
+ while (g < range.first)
+ {
+ intersect_glyphs->add (g);
+ if (!glyphs->next (&g))
+ goto done;
}
- g = rangeRecord[i].last;
+ g = range.last;
}
- while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
- intersect_glyphs->add (g);
+ while (glyphs->next (&g))
+ intersect_glyphs->add (g);
+ done:
return;
}
- hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ unsigned count = rangeRecord.len;
+ if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
{
- if (rangeRecord[i].value != klass) continue;
-
- if (g != HB_SET_VALUE_INVALID)
+ for (hb_codepoint_t g = HB_SET_VALUE_INVALID;
+ glyphs->next (&g);)
{
- if (g >= rangeRecord[i].first &&
- g <= rangeRecord[i].last)
- intersect_glyphs->add (g);
- if (g > rangeRecord[i].last)
- continue;
+ unsigned i;
+ if (rangeRecord.as_array ().bfind (g, &i) &&
+ rangeRecord.arrayZ[i].value == klass)
+ intersect_glyphs->add (g);
}
+ return;
+ }
- 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;
- }
+ for (auto &range : rangeRecord)
+ {
+ if (range.value != klass) continue;
+
+ unsigned end = range.last + 1;
+ for (hb_codepoint_t g = range.first - 1;
+ glyphs->next (&g) && g < end;)
+ intersect_glyphs->add (g);
}
}
@@ -2334,43 +1988,40 @@ struct ClassDefFormat2
{
if (glyphs->is_empty ()) return;
- unsigned count = rangeRecord.len;
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (unsigned int i = 0; i < count; i++)
+ for (auto &range : rangeRecord)
{
- if (!hb_set_next (glyphs, &g))
+ if (!glyphs->next (&g))
break;
- if (g < rangeRecord[i].first)
+ if (g < range.first)
{
intersect_classes->add (0);
break;
}
- g = rangeRecord[i].last;
+ g = range.last;
}
- if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+ if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
intersect_classes->add (0);
- for (const RangeRecord& record : rangeRecord.iter ())
- if (record.intersects (glyphs))
- intersect_classes->add (record.value);
+ for (const auto& range : rangeRecord)
+ if (range.intersects (*glyphs))
+ intersect_classes->add (range.value);
}
protected:
HBUINT16 classFormat; /* Format identifier--format = 2 */
- SortedArray16Of<RangeRecord>
+ typename Types::template SortedArrayOf<RangeRecord<Types>>
rangeRecord; /* Array of glyph ranges--ordered by
* Start GlyphID */
public:
- DEFINE_SIZE_ARRAY (4, rangeRecord);
+ DEFINE_SIZE_ARRAY (2 + Types::size, rangeRecord);
};
struct ClassDef
{
/* Has interface. */
- static constexpr unsigned SENTINEL = 0;
- typedef unsigned int value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
/* Projection. */
hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
@@ -2380,12 +2031,29 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.get_class (glyph_id);
case 2: return u.format2.get_class (glyph_id);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_class (glyph_id);
+ case 4: return u.format4.get_class (glyph_id);
+#endif
default:return 0;
}
}
+ unsigned get_population () const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_population ();
+ case 2: return u.format2.get_population ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.get_population ();
+ case 4: return u.format4.get_population ();
+#endif
+ default:return NOT_COVERED;
+ }
+ }
+
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
{
TRACE_SERIALIZE (this);
@@ -2394,10 +2062,11 @@ struct ClassDef
auto it = + it_with_class_zero | hb_filter (hb_second);
unsigned format = 2;
+ hb_codepoint_t glyph_max = 0;
if (likely (it))
{
hb_codepoint_t glyph_min = (*it).first;
- hb_codepoint_t glyph_max = glyph_min;
+ glyph_max = glyph_min;
unsigned num_glyphs = 0;
unsigned num_ranges = 1;
@@ -2422,12 +2091,22 @@ struct ClassDef
if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
format = 1;
}
+
+#ifndef HB_NO_BEYOND_64K
+ if (glyph_max > 0xFFFFu)
+ format += 2;
+#endif
+
u.format = format;
switch (u.format)
{
case 1: return_trace (u.format1.serialize (c, it));
case 2: return_trace (u.format2.serialize (c, it));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.serialize (c, it));
+ case 4: return_trace (u.format4.serialize (c, it));
+#endif
default:return_trace (false);
}
}
@@ -2442,6 +2121,10 @@ struct ClassDef
switch (u.format) {
case 1: return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
case 2: return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+ case 4: return_trace (u.format4.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#endif
default:return_trace (false);
}
}
@@ -2453,10 +2136,27 @@ struct ClassDef
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+ case 3: return_trace (u.format3.sanitize (c));
+ case 4: return_trace (u.format4.sanitize (c));
+#endif
default:return_trace (true);
}
}
+ unsigned cost () const
+ {
+ switch (u.format) {
+ case 1: return u.format1.cost ();
+ case 2: return u.format2.cost ();
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.cost ();
+ case 4: return u.format4.cost ();
+#endif
+ default:return 0u;
+ }
+ }
+
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
@@ -2465,6 +2165,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.collect_coverage (glyphs);
case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.collect_coverage (glyphs);
+ case 4: return u.format4.collect_coverage (glyphs);
+#endif
default:return false;
}
}
@@ -2477,6 +2181,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.collect_class (glyphs, klass);
case 2: return u.format2.collect_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.collect_class (glyphs, klass);
+ case 4: return u.format4.collect_class (glyphs, klass);
+#endif
default:return false;
}
}
@@ -2486,6 +2194,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersects (glyphs);
+ case 4: return u.format4.intersects (glyphs);
+#endif
default:return false;
}
}
@@ -2494,6 +2206,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.intersects_class (glyphs, klass);
case 2: return u.format2.intersects_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersects_class (glyphs, klass);
+ case 4: return u.format4.intersects_class (glyphs, klass);
+#endif
default:return false;
}
}
@@ -2503,6 +2219,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
case 2: return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+ case 4: return u.format4.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#endif
default:return;
}
}
@@ -2512,6 +2232,10 @@ struct ClassDef
switch (u.format) {
case 1: return u.format1.intersected_classes (glyphs, intersect_classes);
case 2: return u.format2.intersected_classes (glyphs, intersect_classes);
+#ifndef HB_NO_BEYOND_64K
+ case 3: return u.format3.intersected_classes (glyphs, intersect_classes);
+ case 4: return u.format4.intersected_classes (glyphs, intersect_classes);
+#endif
default:return;
}
}
@@ -2519,18 +2243,22 @@ struct ClassDef
protected:
union {
- HBUINT16 format; /* Format identifier */
- ClassDefFormat1 format1;
- ClassDefFormat2 format2;
+ HBUINT16 format; /* Format identifier */
+ ClassDefFormat1_3<SmallTypes> format1;
+ ClassDefFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+ ClassDefFormat1_3<MediumTypes>format3;
+ ClassDefFormat2_4<MediumTypes>format4;
+#endif
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool ClassDef_serialize (hb_serialize_context_t *c,
Iterator it)
-{ c->start_embed<ClassDef> ()->serialize (c, it); }
+{ return (c->start_embed<ClassDef> ()->serialize (c, it)); }
/*
@@ -2578,14 +2306,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.;
@@ -2595,9 +2336,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;
}
@@ -2621,7 +2369,7 @@ struct VarRegionList
{
unsigned int backward = region_map.backward (r);
if (backward >= region_count) return_trace (false);
- memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
+ hb_memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
}
return_trace (true);
@@ -2645,7 +2393,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
@@ -2655,30 +2403,40 @@ 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;
+ unsigned int lcount = is_long ? word_count : 0;
const HBUINT8 *bytes = get_delta_bytes ();
- const HBUINT8 *row = bytes + inner * (scount + count);
+ const HBUINT8 *row = bytes + inner * get_row_size ();
float delta = 0.;
unsigned int i = 0;
- const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
+ const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (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++;
}
@@ -2702,7 +2460,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 ()));
@@ -2717,55 +2475,96 @@ 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 */
+ hb_vector_t<unsigned int> ri_map; /* maps new index to old 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;
+
+ const HBUINT8 *src_delta_bytes = src->get_delta_bytes ();
+ unsigned src_row_size = src->get_row_size ();
+ unsigned src_word_count = src->wordCount ();
+ bool src_long_words = src->longWords ();
+
+ bool has_long = false;
+ if (src_long_words)
+ {
+ for (r = 0; r < src_word_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_fast (old, r, src_delta_bytes, src_row_size);
+ 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++)
{
+ bool short_circuit = src_long_words == has_long && src_word_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_fast (old, r, src_delta_bytes, src_row_size);
+ 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;
+ if (short_circuit)
+ break;
+ }
}
}
- 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++;
+ unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+ ri_map[new_r] = r;
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);
- for (r = 0; r < ri_count; r++)
- if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
+ for (r = 0; r < new_ri_count; r++)
+ regionIndices[r] = region_map[src->regionIndices[ri_map[r]]];
- for (unsigned int i = 0; i < itemCount; i++)
+ HBUINT8 *delta_bytes = get_delta_bytes ();
+ unsigned row_size = get_row_size ();
+ unsigned count = itemCount;
+ for (unsigned int i = 0; i < count; i++)
{
- unsigned int old = inner_map.backward (i);
- for (unsigned int r = 0; r < ri_count; r++)
- if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r));
+ unsigned int old = inner_map.backward (i);
+ for (unsigned int r = 0; r < new_ri_count; r++)
+ set_item_delta_fast (i, r,
+ src->get_item_delta_fast (old, ri_map[r],
+ src_delta_bytes, src_row_size),
+ delta_bytes, row_size);
}
return_trace (true);
@@ -2773,12 +2572,15 @@ struct VarData
void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
{
+ const HBUINT8 *delta_bytes = get_delta_bytes ();
+ unsigned row_size = get_row_size ();
+
for (unsigned int r = 0; r < regionIndices.len; r++)
{
- unsigned int region = regionIndices[r];
+ unsigned int region = regionIndices.arrayZ[r];
if (region_indices.has (region)) continue;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
- if (get_item_delta (inner_map.backward (i), r) != 0)
+ if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0)
{
region_indices.add (region);
break;
@@ -2793,28 +2595,70 @@ 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_fast (unsigned int item, unsigned int region,
+ const HBUINT8 *delta_bytes, unsigned row_size) 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];
+ if (unlikely (item >= itemCount || region >= regionIndices.len)) return 0;
+
+ const HBINT8 *p = (const HBINT8 *) delta_bytes + item * 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];
+ }
+ }
+ int32_t get_item_delta (unsigned int item, unsigned int region) const
+ {
+ return get_item_delta_fast (item, region,
+ get_delta_bytes (),
+ get_row_size ());
}
- void set_item_delta (unsigned int item, unsigned int region, int16_t delta)
+ void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
+ HBUINT8 *delta_bytes, unsigned row_size)
{
- HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
- if (region < shortCount)
- ((HBINT16 *)p)[region] = delta;
+ HBINT8 *p = (HBINT8 *) delta_bytes + item * row_size;
+ 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;
+ }
+ }
+ void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
+ {
+ set_item_delta_fast (item, region, delta,
+ get_delta_bytes (),
+ get_row_size ());
}
+ 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:
@@ -2823,9 +2667,31 @@ struct VarData
struct VariationStore
{
+ using cache_t = VarRegionList::cache_t;
+
+ cache_t *create_cache () const
+ {
+#ifdef HB_NO_VAR
+ return nullptr;
+#endif
+ 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;
@@ -2836,16 +2702,26 @@ 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);
+ }
+ float get_delta (unsigned int index,
+ hb_array_t<int> coords,
+ VarRegionList::cache_t *cache = nullptr) const
+ {
+ return get_delta (index,
+ coords.arrayZ, coords.length,
+ cache);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2863,9 +2739,13 @@ struct VariationStore
bool serialize (hb_serialize_context_t *c,
const VariationStore *src,
- const hb_array_t <hb_inc_bimap_t> &inner_maps)
+ const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
+#ifdef HB_NO_VAR
+ return_trace (false);
+#endif
+
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned int set_count = 0;
@@ -2914,38 +2794,17 @@ struct VariationStore
return_trace (true);
}
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const
{
TRACE_SUBSET (this);
+#ifdef HB_NO_VAR
+ return_trace (false);
+#endif
VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false);
- const hb_set_t *variation_indices = c->plan->layout_variation_indices;
- if (variation_indices->is_empty ()) return_trace (false);
-
- hb_vector_t<hb_inc_bimap_t> inner_maps;
- inner_maps.resize ((unsigned) dataSets.len);
- for (unsigned i = 0; i < inner_maps.length; i++)
- inner_maps[i].init ();
-
- for (unsigned idx : c->plan->layout_variation_indices->iter ())
- {
- uint16_t major = idx >> 16;
- uint16_t minor = idx & 0xFFFF;
-
- if (major >= inner_maps.length)
- {
- for (unsigned i = 0; i < inner_maps.length; i++)
- inner_maps[i].fini ();
- return_trace (false);
- }
- inner_maps[major].add (minor);
- }
- varstore_prime->serialize (c->serializer, this, inner_maps.as_array ());
-
- for (unsigned i = 0; i < inner_maps.length; i++)
- inner_maps[i].fini ();
+ varstore_prime->serialize (c->serializer, this, inner_maps);
return_trace (
!c->serializer->in_error()
@@ -2953,7 +2812,12 @@ struct VariationStore
}
unsigned int get_region_index_count (unsigned int major) const
- { return (this+dataSets[major]).get_region_index_count (); }
+ {
+#ifdef HB_NO_VAR
+ return 0;
+#endif
+ return (this+dataSets[major]).get_region_index_count ();
+ }
void get_region_scalars (unsigned int major,
const int *coords, unsigned int coord_count,
@@ -2971,7 +2835,13 @@ struct VariationStore
&scalars[0], num_scalars);
}
- unsigned int get_sub_table_count () const { return dataSets.len; }
+ unsigned int get_sub_table_count () const
+ {
+#ifdef HB_NO_VAR
+ return 0;
+#endif
+ return dataSets.len;
+ }
protected:
HBUINT16 format;
@@ -2981,9 +2851,18 @@ struct VariationStore
DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
};
+#undef REGION_CACHE_ITEM_CACHE_INVALID
+
/*
* Feature Variations
*/
+enum Cond_with_Var_flag_t
+{
+ KEEP_COND_WITH_VAR = 0,
+ DROP_COND_WITH_VAR = 1,
+ DROP_RECORD_WITH_VAR = 2,
+ MEM_ERR_WITH_VAR = 3,
+};
struct ConditionFormat1
{
@@ -2994,10 +2873,52 @@ struct ConditionFormat1
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (true);
+
+ const hb_map_t *index_map = c->plan->axes_index_map;
+ if (index_map->is_empty ()) return_trace (true);
+
+ if (!index_map->has (axisIndex))
+ return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
private:
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ hb_map_t *condition_map /* OUT */) const
+ {
+ //invalid axis index, drop the entire record
+ if (!c->axes_index_tag_map->has (axisIndex))
+ return DROP_RECORD_WITH_VAR;
+
+ hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
+
+ //axis not pinned, keep the condition
+ if (!c->axes_location->has (axis_tag))
+ {
+ // add axisIndex->value into the hashmap so we can check if the record is
+ // unique with variations
+ int16_t min_val = filterRangeMinValue;
+ int16_t max_val = filterRangeMaxValue;
+ hb_codepoint_t val = (max_val << 16) + min_val;
+
+ condition_map->set (axisIndex, val);
+ return KEEP_COND_WITH_VAR;
+ }
+
+ //axis pinned, check if condition is met
+ //TODO: add check for axis Ranges
+ int v = c->axes_location->get (axis_tag);
+
+ //condition not met, drop the entire record
+ if (v < filterRangeMinValue || v > filterRangeMaxValue)
+ return DROP_RECORD_WITH_VAR;
+
+ //axis pinned and condition met, drop the condition
+ return DROP_COND_WITH_VAR;
+ }
+
bool evaluate (const int *coords, unsigned int coord_len) const
{
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
@@ -3029,6 +2950,15 @@ struct Condition
}
}
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ hb_map_t *condition_map /* OUT */) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.keep_with_variations (c, condition_map);
+ default:return KEEP_COND_WITH_VAR;
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -3070,15 +3000,65 @@ struct ConditionSet
return true;
}
- bool subset (hb_subset_context_t *c) const
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ hb_map_t *condition_map = hb_map_create ();
+ if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
+ hb::shared_ptr<hb_map_t> p {condition_map};
+
+ hb_set_t *cond_set = hb_set_create ();
+ if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
+ hb::shared_ptr<hb_set_t> s {cond_set};
+
+ unsigned num_kept_cond = 0, cond_idx = 0;
+ for (const auto& offset : conditions)
+ {
+ Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
+ // one condition is not met, drop the entire record
+ if (ret == DROP_RECORD_WITH_VAR)
+ return DROP_RECORD_WITH_VAR;
+
+ // axis not pinned, keep this condition
+ if (ret == KEEP_COND_WITH_VAR)
+ {
+ cond_set->add (cond_idx);
+ num_kept_cond++;
+ }
+ cond_idx++;
+ }
+
+ // all conditions met
+ if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
+
+ //check if condition_set is unique with variations
+ if (c->conditionset_map->has (p))
+ //duplicate found, drop the entire record
+ return DROP_RECORD_WITH_VAR;
+
+ c->conditionset_map->set (p, 1);
+ c->record_cond_idx_map->set (c->cur_record_idx, s);
+
+ return KEEP_COND_WITH_VAR;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- + conditions.iter ()
- | hb_apply (subset_offset_array (c, out->conditions, this))
- ;
+ hb_set_t *retained_cond_set = nullptr;
+ if (l->feature_record_cond_idx_map != nullptr)
+ retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
+
+ unsigned int count = conditions.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (retained_cond_set != nullptr && !retained_cond_set->has (i))
+ continue;
+ subset_offset_array (c, out->conditions, this) (conditions[i]);
+ }
return_trace (bool (out->conditions));
}
@@ -3112,10 +3092,19 @@ struct FeatureTableSubstitutionRecord
feature_indexes->add (featureIndex);
}
+ void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+ const hb_set_t *feature_indices,
+ const void *base) const
+ {
+ if (feature_indices->has (featureIndex))
+ feature_substitutes_map->set (featureIndex, &(base+feature));
+ }
+
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
- if (!c->feature_index_map->has (featureIndex)) {
+ if (!c->feature_index_map->has (featureIndex) ||
+ c->feature_substitutes_map->has (featureIndex)) {
// Feature that is being substituted is not being retained, so we don't
// need this.
return_trace (false);
@@ -3157,10 +3146,16 @@ struct FeatureTableSubstitution
}
void collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
+ hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+ | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
+ {
+ if (feature_substitutes_map == nullptr) return true;
+ return !feature_substitutes_map->has (record.featureIndex);
+ })
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
{ r.collect_lookups (this, lookup_indexes); })
;
@@ -3182,6 +3177,12 @@ struct FeatureTableSubstitution
return false;
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ for (const FeatureTableSubstitutionRecord& record : substitutions)
+ record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{
@@ -3221,9 +3222,10 @@ struct FeatureVariationRecord
void collect_lookups (const void *base,
const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
- return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+ return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
}
void closure_features (const void *base,
@@ -3238,13 +3240,25 @@ struct FeatureVariationRecord
return (base+substitutions).intersects_features (feature_index_map);
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ const void *base) const
+ {
+ // ret == 1, all conditions met
+ if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
+ c->apply)
+ {
+ (base+substitutions).collect_feature_substitutes_with_variations (c);
+ c->apply = false; // set variations only once
+ }
+ }
+
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- out->conditions.serialize_subset (c->subset_context, conditions, base);
+ out->conditions.serialize_subset (c->subset_context, conditions, base, c);
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
return_trace (true);
@@ -3294,6 +3308,16 @@ struct FeatureVariations
return (this+record.substitutions).find_substitute (feature_index);
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ c->cur_record_idx = i;
+ varRecords[i].collect_feature_substitutes_with_variations (c, this);
+ }
+ }
+
FeatureVariations* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@@ -3301,17 +3325,25 @@ struct FeatureVariations
}
void collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
for (const FeatureVariationRecord& r : varRecords)
- r.collect_lookups (this, feature_indexes, lookup_indexes);
+ r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
}
void closure_features (const hb_map_t *lookup_indexes,
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *feature_indexes /* OUT */) const
{
- for (const FeatureVariationRecord& record : varRecords)
- record.closure_features (this, lookup_indexes, feature_indexes);
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (feature_record_cond_idx_map != nullptr &&
+ !feature_record_cond_idx_map->has (i))
+ continue;
+ varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
+ }
}
bool subset (hb_subset_context_t *c,
@@ -3333,7 +3365,13 @@ struct FeatureVariations
}
unsigned count = (unsigned) (keep_up_to + 1);
- for (unsigned i = 0; i < count; i++) {
+ for (unsigned i = 0; i < count; i++)
+ {
+ if (l->feature_record_cond_idx_map != nullptr &&
+ !l->feature_record_cond_idx_map->has (i))
+ continue;
+
+ l->cur_feature_var_record_idx = i;
subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
}
return_trace (bool (out->varRecords));
@@ -3448,34 +3486,45 @@ 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
+ VariationDevice* copy (hb_serialize_context_t *c,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
TRACE_SERIALIZE (this);
- auto snap = c->snapshot ();
+ if (!layout_variation_idx_delta_map) return_trace (nullptr);
+
+ hb_pair_t<unsigned, int> *v;
+ if (!layout_variation_idx_delta_map->has (varIdx, &v))
+ return_trace (nullptr);
+
+ c->start_zerocopy (this->static_size);
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out);
- /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */
- if (!layout_variation_idx_map->has (varIdx))
- {
- c->revert (snap);
- return_trace (nullptr);
- }
- unsigned new_idx = layout_variation_idx_map->get (varIdx);
+ unsigned new_idx = hb_first (*v);
out->varIdx = new_idx;
return_trace (out);
}
- void record_variation_index (hb_set_t *layout_variation_indices) const
+ void collect_variation_index (hb_collect_variation_indices_context_t *c) const
{
- layout_variation_indices->add (varIdx);
+ c->layout_variation_indices->add (varIdx);
+ int delta = 0;
+ if (c->font && c->var_store)
+ delta = roundf (get_delta (c->font, *c->var_store, c->store_cache));
+
+ /* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap
+ * varidx later*/
+ c->varidx_delta_map->set (varIdx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -3486,9 +3535,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:
@@ -3511,7 +3562,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)
{
@@ -3521,13 +3574,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)
{
@@ -3537,7 +3592,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;
@@ -3562,7 +3617,8 @@ struct Device
}
}
- Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const
+ Device* copy (hb_serialize_context_t *c,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const
{
TRACE_SERIALIZE (this);
switch (u.b.format) {
@@ -3574,14 +3630,14 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map)));
+ return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_delta_map)));
#endif
default:
return_trace (nullptr);
}
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.b.format) {
#ifndef HB_NO_HINTING
@@ -3592,7 +3648,7 @@ struct Device
#endif
#ifndef HB_NO_VAR
case 0x8000:
- u.variation.record_variation_index (layout_variation_indices);
+ u.variation.collect_variation_index (c);
return;
#endif
default:
@@ -3600,6 +3656,18 @@ struct Device
}
}
+ unsigned get_variation_index () const
+ {
+ switch (u.b.format) {
+#ifndef HB_NO_VAR
+ case 0x8000:
+ return u.variation.varIdx;
+#endif
+ default:
+ return HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ }
+ }
+
protected:
union {
DeviceHeader b;
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index aea644f3e..a84edef16 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -73,7 +73,7 @@ struct AttachList
if (point_count)
{
- + points.sub_array (start_offset, point_count)
+ + points.as_array ().sub_array (start_offset, point_count)
| hb_sink (hb_array (point_array, *point_count))
;
}
@@ -200,15 +200,34 @@ struct CaretValueFormat3
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->embed (this);
+ auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
+ if (!c->serializer->embed (caretValueFormat)) return_trace (false);
+ if (!c->serializer->embed (coordinate)) return_trace (false);
+
+ unsigned varidx = (this+deviceTable).get_variation_index ();
+ if (c->plan->layout_variation_idx_delta_map->has (varidx))
+ {
+ int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (varidx));
+ if (delta != 0)
+ {
+ if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+ }
+
+ if (c->plan->all_axes_pinned)
+ return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+ if (!c->serializer->embed (deviceTable))
+ return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
- hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
+ hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map));
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
- { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ { (this+deviceTable).collect_variation_indices (c); }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -255,14 +274,14 @@ struct CaretValue
}
}
- void collect_variation_indices (hb_set_t *layout_variation_indices) const
+ 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 (layout_variation_indices);
+ u.format3.collect_variation_indices (c);
return;
default: return;
}
@@ -303,7 +322,7 @@ struct LigGlyph
{
if (caret_count)
{
- + carets.sub_array (start_offset, caret_count)
+ + carets.as_array ().sub_array (start_offset, caret_count)
| hb_map (hb_add (this))
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
| hb_sink (hb_array (caret_array, *caret_count))
@@ -329,7 +348,7 @@ struct LigGlyph
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const Offset16To<CaretValue>& offset : carets.iter ())
- (this+offset).collect_variation_indices (c->layout_variation_indices);
+ (this+offset).collect_variation_indices (c);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -510,6 +529,104 @@ struct MarkGlyphSets
*/
+template <typename Types>
+struct GDEFVersion1_2
+{
+ friend struct GDEF;
+
+ protected:
+ FixedVersion<>version; /* Version of the GDEF table--currently
+ * 0x00010003u */
+ typename Types::template OffsetTo<ClassDef>
+ glyphClassDef; /* Offset to class definition table
+ * for glyph type--from beginning of
+ * GDEF header (may be Null) */
+ typename Types::template OffsetTo<AttachList>
+ attachList; /* Offset to list of glyphs with
+ * attachment points--from beginning
+ * of GDEF header (may be Null) */
+ typename Types::template OffsetTo<LigCaretList>
+ ligCaretList; /* Offset to list of positioning points
+ * for ligature carets--from beginning
+ * of GDEF header (may be Null) */
+ typename Types::template OffsetTo<ClassDef>
+ markAttachClassDef; /* Offset to class definition table for
+ * mark attachment type--from beginning
+ * of GDEF header (may be Null) */
+ typename Types::template OffsetTo<MarkGlyphSets>
+ markGlyphSetsDef; /* Offset to the table of mark set
+ * definitions--from beginning of GDEF
+ * header (may be NULL). Introduced
+ * in version 0x00010002. */
+ Offset32To<VariationStore>
+ varStore; /* Offset to the table of Item Variation
+ * Store--from beginning of GDEF
+ * header (may be NULL). Introduced
+ * in version 0x00010003. */
+ public:
+ DEFINE_SIZE_MIN (4 + 4 * Types::size);
+
+ unsigned int get_size () const
+ {
+ return min_size +
+ (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+ (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ glyphClassDef.sanitize (c, this) &&
+ attachList.sanitize (c, this) &&
+ ligCaretList.sanitize (c, this) &&
+ markAttachClassDef.sanitize (c, this) &&
+ (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+ (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+ bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+ bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+ bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+
+ bool subset_markglyphsetsdef = false;
+ if (version.to_int () >= 0x00010002u)
+ {
+ subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+ }
+
+ bool subset_varstore = false;
+ if (version.to_int () >= 0x00010003u)
+ {
+ if (c->plan->all_axes_pinned)
+ out->varStore = 0;
+ else
+ subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+ }
+
+ if (subset_varstore)
+ {
+ out->version.minor = 3;
+ } else if (subset_markglyphsetsdef) {
+ out->version.minor = 2;
+ } else {
+ out->version.minor = 0;
+ }
+
+ return_trace (subset_glyphclassdef || subset_attachlist ||
+ subset_ligcaretlist || subset_markattachclassdef ||
+ (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+ (out->version.to_int () >= 0x00010003u && subset_varstore));
+ }
+};
+
struct GDEF
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
@@ -522,42 +639,190 @@ struct GDEF
ComponentGlyph = 4
};
- bool has_data () const { return version.to_int (); }
- bool has_glyph_classes () const { return glyphClassDef != 0; }
+ unsigned int get_size () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.get_size ();
+#endif
+ default: return u.version.static_size;
+ }
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!u.version.sanitize (c))) return_trace (false);
+ switch (u.version.major) {
+ case 1: return_trace (u.version1.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (u.version2.sanitize (c));
+#endif
+ default: return_trace (true);
+ }
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.subset (c);
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.subset (c);
+#endif
+ default: return false;
+ }
+ }
+
+ bool has_glyph_classes () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.glyphClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.glyphClassDef != 0;
+#endif
+ default: return false;
+ }
+ }
+ const ClassDef &get_glyph_class_def () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.glyphClassDef;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.glyphClassDef;
+#endif
+ default: return Null(ClassDef);
+ }
+ }
+ bool has_attach_list () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.attachList != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.attachList != 0;
+#endif
+ default: return false;
+ }
+ }
+ const AttachList &get_attach_list () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.attachList;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.attachList;
+#endif
+ default: return Null(AttachList);
+ }
+ }
+ bool has_lig_carets () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.ligCaretList != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.ligCaretList != 0;
+#endif
+ default: return false;
+ }
+ }
+ const LigCaretList &get_lig_caret_list () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.ligCaretList;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.ligCaretList;
+#endif
+ default: return Null(LigCaretList);
+ }
+ }
+ bool has_mark_attachment_types () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.markAttachClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.markAttachClassDef != 0;
+#endif
+ default: return false;
+ }
+ }
+ const ClassDef &get_mark_attach_class_def () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.markAttachClassDef;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.markAttachClassDef;
+#endif
+ default: return Null(ClassDef);
+ }
+ }
+ bool has_mark_glyph_sets () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.markGlyphSetsDef != 0;
+#endif
+ default: return false;
+ }
+ }
+ const MarkGlyphSets &get_mark_glyph_sets () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.markGlyphSetsDef;
+#endif
+ default: return Null(MarkGlyphSets);
+ }
+ }
+ bool has_var_store () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.varStore != 0;
+#endif
+ default: return false;
+ }
+ }
+ const VariationStore &get_var_store () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.varStore;
+#endif
+ default: return Null(VariationStore);
+ }
+ }
+
+
+ bool has_data () const { return u.version.to_int (); }
unsigned int get_glyph_class (hb_codepoint_t glyph) const
- { return (this+glyphClassDef).get_class (glyph); }
+ { return get_glyph_class_def ().get_class (glyph); }
void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
- { (this+glyphClassDef).collect_class (glyphs, klass); }
+ { get_glyph_class_def ().collect_class (glyphs, klass); }
- bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
- { return (this+markAttachClassDef).get_class (glyph); }
+ { return get_mark_attach_class_def ().get_class (glyph); }
- bool has_attach_points () const { return attachList != 0; }
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
- { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
+ { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
- bool has_lig_carets () const { return ligCaretList != 0; }
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
- { return (this+ligCaretList).get_lig_carets (font,
- direction, glyph_id, get_var_store(),
- start_offset, caret_count, caret_array); }
+ { return get_lig_caret_list ().get_lig_carets (font,
+ direction, glyph_id, get_var_store(),
+ start_offset, caret_count, caret_array); }
- bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
- { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
-
- bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
- const VariationStore &get_var_store () const
- { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
+ { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
@@ -571,7 +836,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:
@@ -585,35 +850,27 @@ struct GDEF
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
- this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
- if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
+ table = hb_sanitize_context_t ().reference_table<GDEF> (face);
+ if (unlikely (table->is_blocklisted (table.get_blob (), face)))
{
- hb_blob_destroy (this->table.get_blob ());
- this->table = hb_blob_get_empty ();
+ hb_blob_destroy (table.get_blob ());
+ table = hb_blob_get_empty ();
}
}
-
- void fini () { this->table.destroy (); }
+ ~accelerator_t () { table.destroy (); }
hb_blob_ptr_t<GDEF> table;
};
- unsigned int get_size () const
- {
- return min_size +
- (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
- (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
- }
-
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- { (this+ligCaretList).collect_variation_indices (c); }
+ { get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
- hb_map_t *layout_variation_idx_map /* OUT */) const
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
- if (version.to_int () < 0x00010003u || !varStore) return;
+ if (!has_var_store ()) return;
if (layout_variation_indices->is_empty ()) return;
unsigned new_major = 0, new_minor = 0;
@@ -621,7 +878,7 @@ struct GDEF
for (unsigned idx : layout_variation_indices->iter ())
{
uint16_t major = idx >> 16;
- if (major >= (this+varStore).get_sub_table_count ()) break;
+ if (major >= get_var_store ().get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
@@ -629,93 +886,31 @@ struct GDEF
}
unsigned new_idx = (new_major << 16) + new_minor;
- layout_variation_idx_map->set (idx, new_idx);
+ if (!layout_variation_idx_delta_map->has (idx))
+ continue;
+ int delta = hb_second (layout_variation_idx_delta_map->get (idx));
+
+ layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
}
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->embed (*this);
- if (unlikely (!out)) return_trace (false);
-
- bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
- bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
- bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
- bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
- bool subset_markglyphsetsdef = true;
- if (version.to_int () >= 0x00010002u)
- {
- subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
- if (!subset_markglyphsetsdef &&
- version.to_int () == 0x00010002u)
- out->version.minor = 0;
- }
-
- bool subset_varstore = true;
- if (version.to_int () >= 0x00010003u)
- {
- subset_varstore = out->varStore.serialize_subset (c, varStore, this);
- if (!subset_varstore && version.to_int () == 0x00010003u)
- out->version.minor = 2;
- }
-
- return_trace (subset_glyphclassdef || subset_attachlist ||
- subset_ligcaretlist || subset_markattachclassdef ||
- (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
- (out->version.to_int () >= 0x00010003u && subset_varstore));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (version.sanitize (c) &&
- likely (version.major == 1) &&
- glyphClassDef.sanitize (c, this) &&
- attachList.sanitize (c, this) &&
- ligCaretList.sanitize (c, this) &&
- markAttachClassDef.sanitize (c, this) &&
- (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
- (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
- }
-
protected:
- FixedVersion<>version; /* Version of the GDEF table--currently
- * 0x00010003u */
- Offset16To<ClassDef>
- glyphClassDef; /* Offset to class definition table
- * for glyph type--from beginning of
- * GDEF header (may be Null) */
- Offset16To<AttachList>
- attachList; /* Offset to list of glyphs with
- * attachment points--from beginning
- * of GDEF header (may be Null) */
- Offset16To<LigCaretList>
- ligCaretList; /* Offset to list of positioning points
- * for ligature carets--from beginning
- * of GDEF header (may be Null) */
- Offset16To<ClassDef>
- markAttachClassDef; /* Offset to class definition table for
- * mark attachment type--from beginning
- * of GDEF header (may be Null) */
- Offset16To<MarkGlyphSets>
- markGlyphSetsDef; /* Offset to the table of mark set
- * definitions--from beginning of GDEF
- * header (may be NULL). Introduced
- * in version 0x00010002. */
- Offset32To<VariationStore>
- varStore; /* Offset to the table of Item Variation
- * Store--from beginning of GDEF
- * header (may be NULL). Introduced
- * in version 0x00010003. */
+ union {
+ FixedVersion<> version; /* Version identifier */
+ GDEFVersion1_2<SmallTypes> version1;
+#ifndef HB_NO_BEYOND_64K
+ GDEFVersion1_2<MediumTypes> version2;
+#endif
+ } u;
public:
- DEFINE_SIZE_MIN (12);
+ DEFINE_SIZE_MIN (4);
};
-struct GDEF_accelerator_t : GDEF::accelerator_t {};
+struct GDEF_accelerator_t : GDEF::accelerator_t {
+ GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index a8fb5c7ac..8fe987fc5 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -29,2942 +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/GPOS.hh"
namespace OT {
+namespace Layout {
+namespace GPOS_impl {
-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 = HB_DIRECTION_IS_HORIZONTAL (c->direction);
-
- 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);
- 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);
- }
- 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);
- if (!skippy_iter.next ()) 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);
- if (!skippy_iter.next ()) 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)) return_trace (false);
-
- const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
- bool applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
- bool applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
- if (applied_first || applied_second)
- buffer->unsafe_to_break (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);
- if (!skippy_iter.prev ()) return_trace (false);
-
- const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
- if (!prev_record.exitAnchor) return_trace (false);
-
- 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 {
- if (!skippy_iter.prev ()) 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) 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);
- if (!skippy_iter.prev ()) return_trace (false);
-
- /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
- //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
-
- unsigned int j = skippy_iter.idx;
- unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
- if (lig_index == NOT_COVERED) return_trace (false);
-
- const LigatureArray& lig_array = this+ligatureArray;
- const LigatureAttach& lig_attach = lig_array[lig_index];
-
- /* Find component to attach to */
- unsigned int comp_count = lig_attach.rows;
- if (unlikely (!comp_count)) return_trace (false);
-
- /* 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);
- if (!skippy_iter.prev ()) return_trace (false);
-
- if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { 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. */
- return_trace (false);
-
- good:
- unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
- if (mark2_index == NOT_COVERED) 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_UNUSED, 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 int i = 0; i < len; i++)
- propagate_attachment_offsets (pos, len, i, direction);
-}
-
-
-struct GPOS_accelerator_t : GPOS::accelerator_t {};
-
-
+// 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)
@@ -2973,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;
@@ -2993,7 +68,8 @@ template <typename context_t>
}
#endif
-
+} /* namespace GPOS_impl */
+} /* namespace Layout */
} /* namespace OT */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 710c5fbbb..50301ff1d 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -29,1719 +29,13 @@
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
-#include "hb-ot-layout-gsubgpos.hh"
-
+#include "OT/Layout/GSUB/GSUB.hh"
namespace OT {
+namespace Layout {
+namespace GSUB_impl {
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
-template<typename Iterator>
-static void SingleSubst_serialize (hb_serialize_context_t *c,
- Iterator it);
-
-
-struct SingleSubstFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- bool may_have_non_1to1 () const
- { return false; }
-
- void closure (hb_closure_context_t *c) const
- {
- unsigned d = deltaGlyphID;
-
- + hb_iter (this+coverage)
- | hb_filter (c->parent_active_glyphs ())
- | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
- | hb_sink (c->output)
- ;
-
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- unsigned d = deltaGlyphID;
- + hb_iter (this+coverage)
- | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
- | hb_sink (c->output)
- ;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage).get_coverage (glyph_id);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- /* According to the Adobe Annotated OpenType Suite, result is always
- * limited to 16bit. */
- glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
- c->replace_glyph (glyph_id);
-
- return_trace (true);
- }
-
- template<typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c,
- Iterator glyphs,
- unsigned delta)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
- c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- hb_codepoint_t delta = deltaGlyphID;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
- return hb_codepoint_pair_t (g,
- (g + delta) & 0xFFFF); })
- | hb_filter (glyphset, hb_second)
- | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
- { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
- ;
-
- bool ret = bool (it);
- SingleSubst_serialize (c->serializer, it);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of Substitution table */
- HBUINT16 deltaGlyphID; /* Add to original GlyphID to get
- * substitute GlyphID, modulo 0x10000 */
- public:
- DEFINE_SIZE_STATIC (6);
-};
-
-struct SingleSubstFormat2
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- bool may_have_non_1to1 () const
- { return false; }
-
- void closure (hb_closure_context_t *c) const
- {
- + hb_zip (this+coverage, substitute)
- | hb_filter (c->parent_active_glyphs (), hb_first)
- | hb_map (hb_second)
- | hb_sink (c->output)
- ;
-
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- + hb_zip (this+coverage, substitute)
- | hb_map (hb_second)
- | hb_sink (c->output)
- ;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- if (unlikely (index >= substitute.len)) return_trace (false);
-
- c->replace_glyph (substitute[index]);
-
- return_trace (true);
- }
-
- template<typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator,
- hb_codepoint_pair_t))>
- bool serialize (hb_serialize_context_t *c,
- Iterator it)
- {
- TRACE_SERIALIZE (this);
- auto substitutes =
- + it
- | hb_map (hb_second)
- ;
- auto glyphs =
- + it
- | hb_map_retains_sorting (hb_first)
- ;
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
- if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_zip (this+coverage, substitute)
- | hb_filter (glyphset, hb_first)
- | hb_filter (glyphset, hb_second)
- | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
- { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
- ;
-
- bool ret = bool (it);
- SingleSubst_serialize (c->serializer, it);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 2 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of Substitution table */
- Array16Of<HBGlyphID16>
- substitute; /* Array of substitute
- * GlyphIDs--ordered by Coverage Index */
- public:
- DEFINE_SIZE_ARRAY (6, substitute);
-};
-
-struct SingleSubst
-{
-
- template<typename Iterator,
- hb_requires (hb_is_sorted_source_of (Iterator,
- const hb_codepoint_pair_t))>
- bool serialize (hb_serialize_context_t *c,
- Iterator glyphs)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (u.format))) return_trace (false);
- unsigned format = 2;
- unsigned delta = 0;
- if (glyphs)
- {
- format = 1;
- auto get_delta = [=] (hb_codepoint_pair_t _)
- { return (unsigned) (_.second - _.first) & 0xFFFF; };
- delta = get_delta (*glyphs);
- if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
- }
- u.format = format;
- switch (u.format) {
- case 1: return_trace (u.format1.serialize (c,
- + glyphs
- | hb_map_retains_sorting (hb_first),
- delta));
- case 2: return_trace (u.format2.serialize (c, glyphs));
- default:return_trace (false);
- }
- }
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, u.format);
- if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
- switch (u.format) {
- case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
- case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
- default:return_trace (c->default_return_value ());
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- SingleSubstFormat1 format1;
- SingleSubstFormat2 format2;
- } u;
-};
-
-template<typename Iterator>
-static void
-SingleSubst_serialize (hb_serialize_context_t *c,
- Iterator it)
-{ c->start_embed<SingleSubst> ()->serialize (c, it); }
-
-struct Sequence
-{
- bool intersects (const hb_set_t *glyphs) const
- { return hb_all (substitute, glyphs); }
-
- void closure (hb_closure_context_t *c) const
- { c->output->add_array (substitute.arrayZ, substitute.len); }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- { c->output->add_array (substitute.arrayZ, substitute.len); }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- unsigned int count = substitute.len;
-
- /* Special-case to make it in-place and not consider this
- * as a "multiplied" substitution. */
- if (unlikely (count == 1))
- {
- c->replace_glyph (substitute.arrayZ[0]);
- return_trace (true);
- }
- /* Spec disallows this, but Uniscribe allows it.
- * https://github.com/harfbuzz/harfbuzz/issues/253 */
- else if (unlikely (count == 0))
- {
- c->buffer->delete_glyph ();
- return_trace (true);
- }
-
- unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
- HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
- unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
-
- for (unsigned int i = 0; i < count; i++)
- {
- /* If is attached to a ligature, don't disturb that.
- * https://github.com/harfbuzz/harfbuzz/issues/3069 */
- if (!lig_id)
- _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
- c->output_glyph_for_component (substitute.arrayZ[i], klass);
- }
- c->buffer->skip_glyph ();
-
- return_trace (true);
- }
-
- template <typename Iterator,
- hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c,
- Iterator subst)
- {
- TRACE_SERIALIZE (this);
- return_trace (substitute.serialize (c, subst));
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- if (!intersects (&glyphset)) return_trace (false);
-
- auto it =
- + hb_iter (substitute)
- | hb_map (glyph_map)
- ;
-
- auto *out = c->serializer->start_embed (*this);
- return_trace (out->serialize (c->serializer, it));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (substitute.sanitize (c));
- }
-
- protected:
- Array16Of<HBGlyphID16>
- substitute; /* String of GlyphIDs to substitute */
- public:
- DEFINE_SIZE_ARRAY (2, substitute);
-};
-
-struct MultipleSubstFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- bool may_have_non_1to1 () const
- { return true; }
-
- void closure (hb_closure_context_t *c) const
- {
- + hb_zip (this+coverage, sequence)
- | hb_filter (c->parent_active_glyphs (), hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const Sequence &_) { _.closure (c); })
- ;
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- + hb_zip (this+coverage, sequence)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
- ;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
-
- unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- return_trace ((this+sequence[index]).apply (c));
- }
-
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
- for (unsigned int i = 0; i < glyphs.length; i++)
- {
- unsigned int substitute_len = substitute_len_list[i];
- if (unlikely (!sequence[i]
- .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
- return_trace (false);
- substitute_glyphs_list += substitute_len;
- }
- return_trace (coverage.serialize_serialize (c, glyphs));
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->format = format;
-
- hb_sorted_vector_t<hb_codepoint_t> new_coverage;
- + hb_zip (this+coverage, sequence)
- | hb_filter (glyphset, hb_first)
- | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
- out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
- return_trace (bool (new_coverage));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of Substitution table */
- Array16OfOffset16To<Sequence>
- sequence; /* Array of Sequence tables
- * ordered by Coverage Index */
- public:
- DEFINE_SIZE_ARRAY (6, sequence);
-};
-
-struct MultipleSubst
-{
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (u.format))) return_trace (false);
- unsigned int format = 1;
- u.format = format;
- switch (u.format) {
- case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
- default:return_trace (false);
- }
- }
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, u.format);
- if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
- switch (u.format) {
- case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
- default:return_trace (c->default_return_value ());
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- MultipleSubstFormat1 format1;
- } u;
-};
-
-struct AlternateSet
-{
- bool intersects (const hb_set_t *glyphs) const
- { return hb_any (alternates, glyphs); }
-
- void closure (hb_closure_context_t *c) const
- { c->output->add_array (alternates.arrayZ, alternates.len); }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- { c->output->add_array (alternates.arrayZ, alternates.len); }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- unsigned int count = alternates.len;
-
- if (unlikely (!count)) return_trace (false);
-
- hb_mask_t glyph_mask = c->buffer->cur().mask;
- hb_mask_t lookup_mask = c->lookup_mask;
-
- /* Note: This breaks badly if two features enabled this lookup together. */
- unsigned int shift = hb_ctz (lookup_mask);
- unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
-
- /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
- if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
- {
- /* Maybe we can do better than unsafe-to-break all; but since we are
- * changing random state, it would be hard to track that. Good 'nough. */
- c->buffer->unsafe_to_break_all ();
- alt_index = c->random_number () % count + 1;
- }
-
- if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
-
- c->replace_glyph (alternates[alt_index - 1]);
-
- return_trace (true);
- }
-
- unsigned
- get_alternates (unsigned start_offset,
- unsigned *alternate_count /* IN/OUT. May be NULL. */,
- hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
- {
- if (alternates.len && alternate_count)
- {
- + alternates.sub_array (start_offset, alternate_count)
- | hb_sink (hb_array (alternate_glyphs, *alternate_count))
- ;
- }
- return alternates.len;
- }
-
- template <typename Iterator,
- hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c,
- Iterator alts)
- {
- TRACE_SERIALIZE (this);
- return_trace (alternates.serialize (c, alts));
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (alternates)
- | hb_filter (glyphset)
- | hb_map (glyph_map)
- ;
-
- auto *out = c->serializer->start_embed (*this);
- return_trace (out->serialize (c->serializer, it) &&
- out->alternates);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (alternates.sanitize (c));
- }
-
- protected:
- Array16Of<HBGlyphID16>
- alternates; /* Array of alternate GlyphIDs--in
- * arbitrary order */
- public:
- DEFINE_SIZE_ARRAY (2, alternates);
-};
-
-struct AlternateSubstFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- { return (this+coverage).intersects (glyphs); }
-
- bool may_have_non_1to1 () const
- { return false; }
-
- void closure (hb_closure_context_t *c) const
- {
- + hb_zip (this+coverage, alternateSet)
- | hb_filter (c->parent_active_glyphs (), hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
- ;
-
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
- + hb_zip (this+coverage, alternateSet)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
- ;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
- unsigned
- get_glyph_alternates (hb_codepoint_t gid,
- unsigned start_offset,
- unsigned *alternate_count /* IN/OUT. May be NULL. */,
- hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
- { return (this+alternateSet[(this+coverage).get_coverage (gid)])
- .get_alternates (start_offset, alternate_count, alternate_glyphs); }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
-
- unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- return_trace ((this+alternateSet[index]).apply (c));
- }
-
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> alternate_len_list,
- hb_array_t<const HBGlyphID16> alternate_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
- for (unsigned int i = 0; i < glyphs.length; i++)
- {
- unsigned int alternate_len = alternate_len_list[i];
- if (unlikely (!alternateSet[i]
- .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
- return_trace (false);
- alternate_glyphs_list += alternate_len;
- }
- return_trace (coverage.serialize_serialize (c, glyphs));
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->format = format;
-
- hb_sorted_vector_t<hb_codepoint_t> new_coverage;
- + hb_zip (this+coverage, alternateSet)
- | hb_filter (glyphset, hb_first)
- | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
- | hb_map (hb_first)
- | hb_map (glyph_map)
- | hb_sink (new_coverage)
- ;
- out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
- return_trace (bool (new_coverage));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of Substitution table */
- Array16OfOffset16To<AlternateSet>
- alternateSet; /* Array of AlternateSet tables
- * ordered by Coverage Index */
- public:
- DEFINE_SIZE_ARRAY (6, alternateSet);
-};
-
-struct AlternateSubst
-{
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> alternate_len_list,
- hb_array_t<const HBGlyphID16> alternate_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (u.format))) return_trace (false);
- unsigned int format = 1;
- u.format = format;
- switch (u.format) {
- case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
- default:return_trace (false);
- }
- }
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, u.format);
- if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
- switch (u.format) {
- case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
- default:return_trace (c->default_return_value ());
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- AlternateSubstFormat1 format1;
- } u;
-};
-
-
-struct Ligature
-{
- bool intersects (const hb_set_t *glyphs) const
- { return hb_all (component, glyphs); }
-
- void closure (hb_closure_context_t *c) const
- {
- if (!intersects (c->glyphs)) return;
- c->output->add (ligGlyph);
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- c->input->add_array (component.arrayZ, component.get_length ());
- c->output->add (ligGlyph);
- }
-
- bool would_apply (hb_would_apply_context_t *c) const
- {
- if (c->len != component.lenP1)
- return false;
-
- for (unsigned int i = 1; i < c->len; i++)
- if (likely (c->glyphs[i] != component[i]))
- return false;
-
- return true;
- }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- unsigned int count = component.lenP1;
-
- if (unlikely (!count)) return_trace (false);
-
- /* Special-case to make it in-place and not consider this
- * as a "ligated" substitution. */
- if (unlikely (count == 1))
- {
- c->replace_glyph (ligGlyph);
- return_trace (true);
- }
-
- unsigned int total_component_count = 0;
-
- unsigned int match_length = 0;
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
-
- if (likely (!match_input (c, count,
- &component[1],
- match_glyph,
- nullptr,
- &match_length,
- match_positions,
- &total_component_count)))
- return_trace (false);
-
- ligate_input (c,
- count,
- match_positions,
- match_length,
- ligGlyph,
- total_component_count);
-
- return_trace (true);
- }
-
- template <typename Iterator,
- hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
- bool serialize (hb_serialize_context_t *c,
- hb_codepoint_t ligature,
- Iterator components /* Starting from second */)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- ligGlyph = ligature;
- if (unlikely (!component.serialize (c, components))) return_trace (false);
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
- // Ensure Coverage table is always packed after this.
- c->serializer->add_virtual_link (coverage_idx);
-
- auto it =
- + hb_iter (component)
- | hb_map (glyph_map)
- ;
-
- auto *out = c->serializer->start_embed (*this);
- return_trace (out->serialize (c->serializer,
- glyph_map[ligGlyph],
- it));
- }
-
- public:
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
- }
-
- protected:
- HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */
- HeadlessArrayOf<HBGlyphID16>
- component; /* Array of component GlyphIDs--start
- * with the second component--ordered
- * in writing direction */
- public:
- DEFINE_SIZE_ARRAY (4, component);
-};
-
-struct LigatureSet
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return
- + hb_iter (ligature)
- | hb_map (hb_add (this))
- | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
- | hb_any
- ;
- }
-
- void closure (hb_closure_context_t *c) const
- {
- + hb_iter (ligature)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const Ligature &_) { _.closure (c); })
- ;
- }
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- + hb_iter (ligature)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
- ;
- }
-
- bool would_apply (hb_would_apply_context_t *c) const
- {
- return
- + hb_iter (ligature)
- | hb_map (hb_add (this))
- | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
- | hb_any
- ;
- }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- unsigned int num_ligs = ligature.len;
- for (unsigned int i = 0; i < num_ligs; i++)
- {
- const Ligature &lig = this+ligature[i];
- if (lig.apply (c)) return_trace (true);
- }
-
- return_trace (false);
- }
-
- bool serialize (hb_serialize_context_t *c,
- hb_array_t<const HBGlyphID16> ligatures,
- hb_array_t<const unsigned int> component_count_list,
- hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
- for (unsigned int i = 0; i < ligatures.length; i++)
- {
- unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
- if (unlikely (!ligature[i].serialize_serialize (c,
- ligatures[i],
- component_list.sub_array (0, component_count))))
- return_trace (false);
- component_list += component_count;
- }
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- + hb_iter (ligature)
- | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
- | hb_drain
- ;
-
- if (bool (out->ligature))
- // Ensure Coverage table is always packed after this.
- c->serializer->add_virtual_link (coverage_idx);
-
- return_trace (bool (out->ligature));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (ligature.sanitize (c, this));
- }
-
- protected:
- Array16OfOffset16To<Ligature>
- ligature; /* Array LigatureSet tables
- * ordered by preference */
- public:
- DEFINE_SIZE_ARRAY (2, ligature);
-};
-
-struct LigatureSubstFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- return
- + hb_zip (this+coverage, ligatureSet)
- | hb_filter (*glyphs, hb_first)
- | hb_map (hb_second)
- | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
- { return (this+_).intersects (glyphs); })
- | hb_any
- ;
- }
-
- bool may_have_non_1to1 () const
- { return true; }
-
- void closure (hb_closure_context_t *c) const
- {
- + hb_zip (this+coverage, ligatureSet)
- | hb_filter (c->parent_active_glyphs (), hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
- ;
-
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
- + hb_zip (this+coverage, ligatureSet)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
- ;
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- {
- unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
- if (likely (index == NOT_COVERED)) return false;
-
- const LigatureSet &lig_set = this+ligatureSet[index];
- return lig_set.would_apply (c);
- }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
-
- unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- const LigatureSet &lig_set = this+ligatureSet[index];
- return_trace (lig_set.apply (c));
- }
-
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> first_glyphs,
- hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
- hb_array_t<const HBGlyphID16> ligatures_list,
- hb_array_t<const unsigned int> component_count_list,
- hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (this))) return_trace (false);
- if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
- for (unsigned int i = 0; i < first_glyphs.length; i++)
- {
- unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
- if (unlikely (!ligatureSet[i]
- .serialize_serialize (c,
- ligatures_list.sub_array (0, ligature_count),
- component_count_list.sub_array (0, ligature_count),
- component_list))) return_trace (false);
- ligatures_list += ligature_count;
- component_count_list += ligature_count;
- }
- return_trace (coverage.serialize_serialize (c, first_glyphs));
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->format = format;
-
- // Due to a bug in some older versions of windows 7 the Coverage table must be
- // packed after the LigatureSet and Ligature tables, so serialize Coverage first
- // which places it last in the packed order.
- hb_set_t new_coverage;
- + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
- | hb_filter (glyphset, hb_first)
- | hb_filter ([&] (const LigatureSet& _) {
- return _.intersects (&glyphset);
- }, hb_second)
- | hb_map (hb_first)
- | hb_sink (new_coverage);
-
- if (!c->serializer->push<Coverage> ()
- ->serialize (c->serializer,
- + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
- {
- c->serializer->pop_discard ();
- return_trace (false);
- }
-
- unsigned coverage_idx = c->serializer->pop_pack ();
- c->serializer->add_link (out->coverage, coverage_idx);
-
- + hb_zip (this+coverage, ligatureSet)
- | hb_filter (new_coverage, hb_first)
- | hb_map (hb_second)
- // to ensure that the repacker always orders the coverage table after the LigatureSet
- // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
- // the coverage table object idx is passed down to facilitate this.
- | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
- ;
-
- return_trace (bool (new_coverage));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of Substitution table */
- Array16OfOffset16To<LigatureSet>
- ligatureSet; /* Array LigatureSet tables
- * ordered by Coverage Index */
- public:
- DEFINE_SIZE_ARRAY (6, ligatureSet);
-};
-
-struct LigatureSubst
-{
- bool serialize (hb_serialize_context_t *c,
- hb_sorted_array_t<const HBGlyphID16> first_glyphs,
- hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
- hb_array_t<const HBGlyphID16> ligatures_list,
- hb_array_t<const unsigned int> component_count_list,
- hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (u.format))) return_trace (false);
- unsigned int format = 1;
- u.format = format;
- switch (u.format) {
- case 1: return_trace (u.format1.serialize (c,
- first_glyphs,
- ligature_per_first_glyph_count_list,
- ligatures_list,
- component_count_list,
- component_list));
- default:return_trace (false);
- }
- }
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, u.format);
- if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
- switch (u.format) {
- case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
- default:return_trace (c->default_return_value ());
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- LigatureSubstFormat1 format1;
- } u;
-};
-
-
-struct ContextSubst : Context {};
-
-struct ChainContextSubst : ChainContext {};
-
-struct ExtensionSubst : Extension<ExtensionSubst>
-{
- typedef struct SubstLookupSubTable SubTable;
- bool is_reverse () const;
-};
-
-
-struct ReverseChainSingleSubstFormat1
-{
- bool intersects (const hb_set_t *glyphs) const
- {
- if (!(this+coverage).intersects (glyphs))
- return false;
-
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-
- unsigned int count;
-
- count = backtrack.len;
- for (unsigned int i = 0; i < count; i++)
- if (!(this+backtrack[i]).intersects (glyphs))
- return false;
-
- count = lookahead.len;
- for (unsigned int i = 0; i < count; i++)
- if (!(this+lookahead[i]).intersects (glyphs))
- return false;
-
- return true;
- }
-
- bool may_have_non_1to1 () const
- { return false; }
-
- void closure (hb_closure_context_t *c) const
- {
- if (!intersects (c->glyphs)) return;
-
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
- + hb_zip (this+coverage, substitute)
- | hb_filter (c->parent_active_glyphs (), hb_first)
- | hb_map (hb_second)
- | hb_sink (c->output)
- ;
- }
-
- void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
- void collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
- unsigned int count;
-
- count = backtrack.len;
- for (unsigned int i = 0; i < count; i++)
- if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
-
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- count = lookahead.len;
- for (unsigned int i = 0; i < count; i++)
- if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
-
- const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
- count = substitute.len;
- c->output->add_array (substitute.arrayZ, substitute.len);
- }
-
- const Coverage &get_coverage () const { return this+coverage; }
-
- bool would_apply (hb_would_apply_context_t *c) const
- { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
- return_trace (false); /* No chaining to this type */
-
- unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
- if (likely (index == NOT_COVERED)) return_trace (false);
-
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
- if (unlikely (index >= substitute.len)) return_trace (false);
-
- unsigned int start_index = 0, end_index = 0;
- if (match_backtrack (c,
- backtrack.len, (HBUINT16 *) backtrack.arrayZ,
- match_coverage, this,
- &start_index) &&
- match_lookahead (c,
- lookahead.len, (HBUINT16 *) lookahead.arrayZ,
- match_coverage, this,
- 1, &end_index))
- {
- c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
- c->replace_glyph_inplace (substitute[index]);
- /* Note: We DON'T decrease buffer->idx. The main loop does it
- * for us. This is useful for preventing surprises if someone
- * calls us through a Context lookup. */
- return_trace (true);
- }
-
- return_trace (false);
- }
-
- template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
- {
- TRACE_SERIALIZE (this);
- auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
-
- if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
- return_trace (false);
-
- for (auto& offset : it) {
- auto *o = out->serialize_append (c->serializer);
- if (unlikely (!o) || !o->serialize_subset (c, offset, this))
- return_trace (false);
- }
-
- return_trace (true);
- }
-
- template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
- hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
- hb_requires (hb_is_iterator (BacktrackIterator)),
- hb_requires (hb_is_iterator (LookaheadIterator))>
- bool serialize (hb_subset_context_t *c,
- Iterator coverage_subst_iter,
- BacktrackIterator backtrack_iter,
- LookaheadIterator lookahead_iter) const
- {
- TRACE_SERIALIZE (this);
-
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->check_success (out))) return_trace (false);
- if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
- if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
-
- if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
- if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
-
- auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
- auto substitutes =
- + coverage_subst_iter
- | hb_map (hb_second)
- ;
-
- auto glyphs =
- + coverage_subst_iter
- | hb_map_retains_sorting (hb_first)
- ;
- if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
- return_trace (false);
-
- if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
- return_trace (false);
- return_trace (true);
- }
-
- bool subset (hb_subset_context_t *c) const
- {
- TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
- auto it =
- + hb_zip (this+coverage, substitute)
- | hb_filter (glyphset, hb_first)
- | hb_filter (glyphset, hb_second)
- | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
- { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
- ;
-
- return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
- return_trace (false);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- if (!lookahead.sanitize (c, this))
- return_trace (false);
- const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
- return_trace (substitute.sanitize (c));
- }
-
- protected:
- HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
- coverage; /* Offset to Coverage table--from
- * beginning of table */
- Array16OfOffset16To<Coverage>
- backtrack; /* Array of coverage tables
- * in backtracking sequence, in glyph
- * sequence order */
- Array16OfOffset16To<Coverage>
- lookaheadX; /* Array of coverage tables
- * in lookahead sequence, in glyph
- * sequence order */
- Array16Of<HBGlyphID16>
- substituteX; /* Array of substitute
- * GlyphIDs--ordered by Coverage Index */
- public:
- DEFINE_SIZE_MIN (10);
-};
-
-struct ReverseChainSingleSubst
-{
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, u.format);
- if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
- switch (u.format) {
- case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
- default:return_trace (c->default_return_value ());
- }
- }
-
- protected:
- union {
- HBUINT16 format; /* Format identifier */
- ReverseChainSingleSubstFormat1 format1;
- } u;
-};
-
-
-
-/*
- * SubstLookup
- */
-
-struct SubstLookupSubTable
-{
- friend struct Lookup;
- friend struct SubstLookup;
-
- enum Type {
- Single = 1,
- Multiple = 2,
- Alternate = 3,
- Ligature = 4,
- Context = 5,
- ChainContext = 6,
- Extension = 7,
- ReverseChainSingle = 8
- };
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
- {
- TRACE_DISPATCH (this, lookup_type);
- switch (lookup_type) {
- case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
- case Multiple: return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
- case Alternate: return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
- case Ligature: return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
- case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
- case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
- case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
- case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
- default: return_trace (c->default_return_value ());
- }
- }
-
- bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
- {
- hb_intersects_context_t c (glyphs);
- return dispatch (&c, lookup_type);
- }
-
- protected:
- union {
- SingleSubst single;
- MultipleSubst multiple;
- AlternateSubst alternate;
- LigatureSubst ligature;
- ContextSubst context;
- ChainContextSubst chainContext;
- ExtensionSubst extension;
- ReverseChainSingleSubst reverseChainContextSingle;
- } u;
- public:
- DEFINE_SIZE_MIN (0);
-};
-
-
-struct SubstLookup : Lookup
-{
- typedef SubstLookupSubTable SubTable;
-
- const SubTable& get_subtable (unsigned int i) const
- { return Lookup::get_subtable<SubTable> (i); }
-
- static inline bool lookup_type_is_reverse (unsigned int lookup_type)
- { return lookup_type == SubTable::ReverseChainSingle; }
-
- bool is_reverse () const
- {
- unsigned int type = get_type ();
- if (unlikely (type == SubTable::Extension))
- return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
- return lookup_type_is_reverse (type);
- }
-
- bool may_have_non_1to1 () const
- {
- hb_have_non_1to1_context_t c;
- return dispatch (&c);
- }
-
- bool apply (hb_ot_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- return_trace (dispatch (c));
- }
-
- bool intersects (const hb_set_t *glyphs) const
- {
- hb_intersects_context_t c (glyphs);
- return dispatch (&c);
- }
-
- hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
- {
- if (!c->should_visit_lookup (this_index))
- return hb_closure_context_t::default_return_value ();
-
- c->set_recurse_func (dispatch_closure_recurse_func);
-
- hb_closure_context_t::return_t ret = dispatch (c);
-
- c->flush ();
-
- return ret;
- }
-
- hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
- {
- if (c->is_lookup_visited (this_index))
- return hb_closure_lookups_context_t::default_return_value ();
-
- c->set_lookup_visited (this_index);
- if (!intersects (c->glyphs))
- {
- c->set_lookup_inactive (this_index);
- return hb_closure_lookups_context_t::default_return_value ();
- }
-
- c->set_recurse_func (dispatch_closure_lookups_recurse_func);
-
- hb_closure_lookups_context_t::return_t ret = dispatch (c);
- return ret;
- }
-
- hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
- {
- c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
- return dispatch (c);
- }
-
- template <typename set_t>
- void collect_coverage (set_t *glyphs) const
- {
- hb_collect_coverage_context_t<set_t> c (glyphs);
- dispatch (&c);
- }
-
- bool would_apply (hb_would_apply_context_t *c,
- const hb_ot_layout_lookup_accelerator_t *accel) const
- {
- if (unlikely (!c->len)) return false;
- if (!accel->may_have (c->glyphs[0])) return false;
- return dispatch (c);
- }
-
- static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
- bool serialize_single (hb_serialize_context_t *c,
- uint32_t lookup_props,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const HBGlyphID16> substitutes)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
- if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
- {
- c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
- return_trace (true);
- }
- c->pop_discard ();
- return_trace (false);
- }
-
- bool serialize_multiple (hb_serialize_context_t *c,
- uint32_t lookup_props,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> substitute_len_list,
- hb_array_t<const HBGlyphID16> substitute_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
- if (c->push<SubTable> ()->u.multiple.
- serialize (c,
- glyphs,
- substitute_len_list,
- substitute_glyphs_list))
- {
- c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
- return_trace (true);
- }
- c->pop_discard ();
- return_trace (false);
- }
-
- bool serialize_alternate (hb_serialize_context_t *c,
- uint32_t lookup_props,
- hb_sorted_array_t<const HBGlyphID16> glyphs,
- hb_array_t<const unsigned int> alternate_len_list,
- hb_array_t<const HBGlyphID16> alternate_glyphs_list)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-
- if (c->push<SubTable> ()->u.alternate.
- serialize (c,
- glyphs,
- alternate_len_list,
- alternate_glyphs_list))
- {
- c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
- return_trace (true);
- }
- c->pop_discard ();
- return_trace (false);
- }
-
- bool serialize_ligature (hb_serialize_context_t *c,
- uint32_t lookup_props,
- hb_sorted_array_t<const HBGlyphID16> first_glyphs,
- hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
- hb_array_t<const HBGlyphID16> ligatures_list,
- hb_array_t<const unsigned int> component_count_list,
- hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
- {
- TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
- if (c->push<SubTable> ()->u.ligature.
- serialize (c,
- first_glyphs,
- ligature_per_first_glyph_count_list,
- ligatures_list,
- component_count_list,
- component_list))
- {
- c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
- return_trace (true);
- }
- c->pop_discard ();
- return_trace (false);
- }
-
- template <typename context_t>
- static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
- static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
-
- static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
- {
- if (!c->should_visit_lookup (lookup_index))
- return hb_empty_t ();
-
- hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
-
- /* While in theory we should flush here, it will cause timeouts because a recursive
- * lookup can keep growing the glyph set. Skip, and outer loop will retry up to
- * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
- //c->flush ();
-
- return ret;
- }
-
- HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
-
- template <typename context_t, typename ...Ts>
- typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
- { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
-
- bool subset (hb_subset_context_t *c) const
- { return Lookup::subset<SubTable> (c); }
-
- bool sanitize (hb_sanitize_context_t *c) const
- { return Lookup::sanitize<SubTable> (c); }
-};
-
-/*
- * GSUB -- Glyph Substitution
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
- */
-
-struct GSUB : GSUBGPOS
-{
- static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
-
- const SubstLookup& get_lookup (unsigned int i) const
- { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
-
- bool subset (hb_subset_context_t *c) const
- {
- hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
- return GSUBGPOS::subset<SubstLookup> (&l);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- { return GSUBGPOS::sanitize<SubstLookup> (c); }
-
- HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
- hb_face_t *face) const;
-
- void closure_lookups (hb_face_t *face,
- const hb_set_t *glyphs,
- hb_set_t *lookup_indexes /* IN/OUT */) const
- { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
-
- typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
-};
-
-
-struct GSUB_accelerator_t : GSUB::accelerator_t {};
-
-
+// TODO(garretrieger): Move into the new layout directory.
/* Out-of-class implementation for methods recursing */
#ifndef HB_NO_OT_LAYOUT
@@ -1764,13 +58,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;
@@ -1784,7 +81,8 @@ template <typename context_t>
}
#endif
-
+} /* namespace GSUB_impl */
+} /* namespace Layout */
} /* namespace OT */
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index c0ed2bcc0..04ccefd10 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -81,12 +81,15 @@ struct hb_closure_context_t :
nesting_level_left++;
}
+ void reset_lookup_visit_count ()
+ { lookup_count = 0; }
+
bool lookup_limit_exceeded ()
- { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+ { return lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; }
bool should_visit_lookup (unsigned int lookup_index)
{
- if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+ if (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT)
return false;
if (is_lookup_done (lookup_index))
@@ -97,8 +100,8 @@ struct hb_closure_context_t :
bool is_lookup_done (unsigned int lookup_index)
{
- if (done_lookups_glyph_count->in_error () ||
- done_lookups_glyph_set->in_error ())
+ if (unlikely (done_lookups_glyph_count->in_error () ||
+ done_lookups_glyph_set->in_error ()))
return true;
/* Have we visited this lookup with the current set of glyphs? */
@@ -106,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));
@@ -122,29 +121,36 @@ struct hb_closure_context_t :
hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
if (unlikely (covered_glyph_set->in_error ()))
return true;
- if (parent_active_glyphs ()->is_subset (*covered_glyph_set))
+ if (parent_active_glyphs ().is_subset (*covered_glyph_set))
return true;
- hb_set_union (covered_glyph_set, parent_active_glyphs ());
+ covered_glyph_set->union_ (parent_active_glyphs ());
return false;
}
- hb_set_t* parent_active_glyphs ()
+ const hb_set_t& previous_parent_active_glyphs () {
+ if (active_glyphs_stack.length <= 1)
+ return *glyphs;
+
+ return active_glyphs_stack[active_glyphs_stack.length - 2];
+ }
+
+ const hb_set_t& parent_active_glyphs ()
{
- if (active_glyphs_stack.length < 1)
- return glyphs;
+ if (!active_glyphs_stack)
+ return *glyphs;
return active_glyphs_stack.tail ();
}
- void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set)
+ hb_set_t& push_cur_active_glyphs ()
{
- active_glyphs_stack.push (cur_active_glyph_set);
+ return *active_glyphs_stack.push ();
}
bool pop_cur_done_glyphs ()
{
- if (active_glyphs_stack.length < 1)
+ if (!active_glyphs_stack)
return false;
active_glyphs_stack.pop ();
@@ -153,29 +159,22 @@ struct hb_closure_context_t :
hb_face_t *face;
hb_set_t *glyphs;
- hb_set_t *cur_intersected_glyphs;
hb_set_t output[1];
- hb_vector_t<hb_set_t *> active_glyphs_stack;
- recurse_func_t recurse_func;
+ hb_vector_t<hb_set_t> active_glyphs_stack;
+ recurse_func_t recurse_func = nullptr;
unsigned int nesting_level_left;
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
- hb_set_t *cur_intersected_glyphs_,
hb_map_t *done_lookups_glyph_count_,
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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_),
- cur_intersected_glyphs (cur_intersected_glyphs_),
- recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
done_lookups_glyph_count (done_lookups_glyph_count_),
- done_lookups_glyph_set (done_lookups_glyph_set_),
- lookup_count (0)
- {
- push_cur_active_glyphs (glyphs_);
- }
+ done_lookups_glyph_set (done_lookups_glyph_set_)
+ {}
~hb_closure_context_t () { flush (); }
@@ -183,17 +182,17 @@ struct hb_closure_context_t :
void flush ()
{
- hb_set_del_range (output, face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */
- hb_set_union (glyphs, output);
- hb_set_clear (output);
+ output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */
+ glyphs->union_ (*output);
+ output->clear ();
active_glyphs_stack.pop ();
- active_glyphs_stack.fini ();
+ active_glyphs_stack.reset ();
}
private:
hb_map_t *done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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;
};
@@ -211,7 +210,11 @@ struct hb_closure_lookups_context_t :
return;
/* Return if new lookup was recursed to before. */
- if (is_lookup_visited (lookup_index))
+ if (lookup_limit_exceeded ()
+ || visited_lookups->in_error ()
+ || visited_lookups->has (lookup_index))
+ // Don't increment lookup count here, that will be done in the call to closure_lookups()
+ // made by recurse_func.
return;
nesting_level_left--;
@@ -226,12 +229,20 @@ struct hb_closure_lookups_context_t :
{ inactive_lookups->add (lookup_index); }
bool lookup_limit_exceeded ()
- { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+ {
+ bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT;
+ if (ret)
+ DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!");
+ return ret; }
bool is_lookup_visited (unsigned lookup_index)
{
- if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
+ if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.",
+ lookup_count, lookup_index);
return true;
+ }
if (unlikely (visited_lookups->in_error ()))
return true;
@@ -383,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>
{
@@ -391,22 +401,22 @@ struct hb_ot_apply_context_t :
{
matcher_t () :
lookup_props (0),
+ mask (-1),
ignore_zwnj (false),
ignore_zwj (false),
- mask (-1),
-#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
- syllable arg1(0),
-#undef arg1
+ per_syllable (false),
+ syllable {0},
match_func (nullptr),
match_data (nullptr) {}
- 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, unsigned 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_; }
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
void set_mask (hb_mask_t mask_) { mask = mask_; }
- void set_syllable (uint8_t syllable_) { syllable = syllable_; }
+ void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
+ void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; }
void set_match_func (match_func_t match_func_,
const void *match_data_)
{ match_func = match_func_; match_data = match_data_; }
@@ -417,15 +427,15 @@ struct hb_ot_apply_context_t :
MATCH_MAYBE
};
- may_match_t may_match (const hb_glyph_info_t &info,
- const HBUINT16 *glyph_data) const
+ may_match_t may_match (hb_glyph_info_t &info,
+ hb_codepoint_t glyph_data) const
{
if (!(info.mask & mask) ||
(syllable && syllable != info.syllable ()))
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;
}
@@ -452,9 +462,10 @@ struct hb_ot_apply_context_t :
protected:
unsigned int lookup_props;
+ hb_mask_t mask;
bool ignore_zwnj;
bool ignore_zwj;
- hb_mask_t mask;
+ bool per_syllable;
uint8_t syllable;
match_func_t match_func;
const void *match_data;
@@ -465,7 +476,10 @@ struct hb_ot_apply_context_t :
void init (hb_ot_apply_context_t *c_, bool context_match = false)
{
c = c_;
- match_glyph_data = nullptr;
+ match_glyph_data16 = nullptr;
+#ifndef HB_NO_BEYOND_64K
+ match_glyph_data24 = nullptr;
+#endif
matcher.set_match_func (nullptr, nullptr);
matcher.set_lookup_props (c->lookup_props);
/* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
@@ -473,18 +487,31 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
+ matcher.set_per_syllable (c->per_syllable);
}
void set_lookup_props (unsigned int lookup_props)
{
matcher.set_lookup_props (lookup_props);
}
void set_match_func (matcher_t::match_func_t match_func_,
- const void *match_data_,
- const HBUINT16 glyph_data[])
+ const void *match_data_)
{
matcher.set_match_func (match_func_, match_data_);
- match_glyph_data = glyph_data;
}
+ void set_glyph_data (const HBUINT16 glyph_data[])
+ {
+ match_glyph_data16 = glyph_data;
+#ifndef HB_NO_BEYOND_64K
+ match_glyph_data24 = nullptr;
+#endif
+ }
+#ifndef HB_NO_BEYOND_64K
+ void set_glyph_data (const HBUINT24 glyph_data[])
+ {
+ match_glyph_data16 = nullptr;
+ match_glyph_data24 = glyph_data;
+ }
+#endif
void reset (unsigned int start_index_,
unsigned int num_items_)
@@ -498,73 +525,127 @@ struct hb_ot_apply_context_t :
void reject ()
{
num_items++;
- if (match_glyph_data) match_glyph_data--;
+ backup_glyph_data ();
}
matcher_t::may_skip_t
may_skip (const hb_glyph_info_t &info) const
{ return matcher.may_skip (c, info); }
- bool next ()
+ bool next (unsigned *unsafe_to = nullptr)
{
assert (num_items > 0);
- while (idx + num_items < end)
+ /* The alternate condition below is faster at string boundaries,
+ * but produces subpar "unsafe-to-concat" values. */
+ signed stop = (signed) end - (signed) num_items;
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
+ stop = (signed) end - 1;
+ while ((signed) idx < stop)
{
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))
continue;
- matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+ matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
if (match == matcher_t::MATCH_YES ||
(match == matcher_t::MATCH_MAYBE &&
skip == matcher_t::SKIP_NO))
{
num_items--;
- if (match_glyph_data) match_glyph_data++;
+ advance_glyph_data ();
return true;
}
if (skip == matcher_t::SKIP_NO)
+ {
+ if (unsafe_to)
+ *unsafe_to = idx + 1;
return false;
+ }
}
+ if (unsafe_to)
+ *unsafe_to = end;
return false;
}
- bool prev ()
+ bool prev (unsigned *unsafe_from = nullptr)
{
assert (num_items > 0);
- while (idx > num_items - 1)
+ /* The alternate condition below is faster at string boundaries,
+ * but produces subpar "unsafe-to-concat" values. */
+ unsigned stop = num_items - 1;
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
+ stop = 1 - 1;
+ while (idx > stop)
{
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))
continue;
- matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+ matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
if (match == matcher_t::MATCH_YES ||
(match == matcher_t::MATCH_MAYBE &&
skip == matcher_t::SKIP_NO))
{
num_items--;
- if (match_glyph_data) match_glyph_data++;
+ advance_glyph_data ();
return true;
}
if (skip == matcher_t::SKIP_NO)
+ {
+ if (unsafe_from)
+ *unsafe_from = hb_max (1u, idx) - 1u;
return false;
+ }
}
+ if (unsafe_from)
+ *unsafe_from = 0;
return false;
}
+ hb_codepoint_t
+ get_glyph_data ()
+ {
+ if (match_glyph_data16) return *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+ else
+ if (match_glyph_data24) return *match_glyph_data24;
+#endif
+ return 0;
+ }
+ void
+ advance_glyph_data ()
+ {
+ if (match_glyph_data16) match_glyph_data16++;
+#ifndef HB_NO_BEYOND_64K
+ else
+ if (match_glyph_data24) match_glyph_data24++;
+#endif
+ }
+ void
+ backup_glyph_data ()
+ {
+ if (match_glyph_data16) match_glyph_data16--;
+#ifndef HB_NO_BEYOND_64K
+ else
+ if (match_glyph_data24) match_glyph_data24--;
+#endif
+ }
+
unsigned int idx;
protected:
hb_ot_apply_context_t *c;
matcher_t matcher;
- const HBUINT16 *match_glyph_data;
+ const HBUINT16 *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+ const HBUINT24 *match_glyph_data24;
+#endif
unsigned int num_items;
unsigned int end;
@@ -580,7 +661,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);
@@ -590,34 +674,35 @@ 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_set_digest_t digest;
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 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
@@ -626,17 +711,24 @@ 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
+ ),
+ digest (buffer_->digest ()),
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),
- 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 ()
{
@@ -647,6 +739,7 @@ struct hb_ot_apply_context_t :
void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
+ void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
void set_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
@@ -697,117 +790,222 @@ struct hb_ot_apply_context_t :
return true;
}
- void _set_glyph_props (hb_codepoint_t glyph_index,
+ void _set_glyph_class (hb_codepoint_t glyph_index,
unsigned int class_guess = 0,
bool ligature = false,
- bool component = false) const
+ bool component = false)
{
- unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
- HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+ digest.add (glyph_index);
+
+ 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)
{
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
+ props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
/* In the only place that the MULTIPLIED bit is used, Uniscribe
* seems to only care about the "last" transformation between
* Ligature and Multiple substitutions. Ie. if you ligate, expand,
* and ligate again, it forgives the multiplication and acts as
* if only ligation happened. As such, clear MULTIPLIED bit.
*/
- add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
if (component)
- add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
if (likely (has_glyph_classes))
- _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
+ {
+ props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
+ }
else if (class_guess)
- _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
+ {
+ props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess);
+ }
+ else
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
}
- void replace_glyph (hb_codepoint_t glyph_index) const
+ void replace_glyph (hb_codepoint_t glyph_index)
{
- _set_glyph_props (glyph_index);
+ _set_glyph_class (glyph_index);
(void) buffer->replace_glyph (glyph_index);
}
- void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+ void replace_glyph_inplace (hb_codepoint_t glyph_index)
{
- _set_glyph_props (glyph_index);
+ _set_glyph_class (glyph_index);
buffer->cur().codepoint = glyph_index;
}
void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess)
{
- _set_glyph_props (glyph_index, class_guess, true);
+ _set_glyph_class (glyph_index, class_guess, true);
(void) buffer->replace_glyph (glyph_index);
}
void output_glyph_for_component (hb_codepoint_t glyph_index,
- unsigned int class_guess) const
+ unsigned int class_guess)
{
- _set_glyph_props (glyph_index, class_guess, false, true);
+ _set_glyph_class (glyph_index, class_guess, false, true);
(void) buffer->output_glyph (glyph_index);
}
};
-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)
+ static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c)
{
const Type *typed_obj = (const Type *) obj;
return typed_obj->apply (c);
}
- typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ template <typename T>
+ static inline auto apply_cached_ (const T *obj, 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, 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, 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, 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, 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, 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, hb_ot_apply_context_t *c);
+ typedef bool (*hb_cache_func_t) (const void *obj, 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);
}
- bool apply (OT::hb_ot_apply_context_t *c) const
+ bool apply (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
}
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ bool apply_cached (hb_ot_apply_context_t *c) const
+ {
+ return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
+ }
+ bool cache_enter (hb_ot_apply_context_t *c) const
+ {
+ return cache_func (obj, c, true);
+ }
+ void cache_leave (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 (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data, void *cache);
+typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
+typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
struct ContextClosureFuncs
{
@@ -822,100 +1020,150 @@ 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)
+static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED, void *cache HB_UNUSED)
{
return glyphs->has (value);
}
-static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data, void *cache)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- return class_def.intersects_class (glyphs, value);
+ hb_map_t *map = (hb_map_t *) cache;
+
+ hb_codepoint_t *cached_v;
+ if (map->has (value, &cached_v))
+ return *cached_v;
+
+ bool v = class_def.intersects_class (glyphs, value);
+ map->set (value, v);
+
+ return v;
}
-static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED)
{
- const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+ Offset16To<Coverage> coverage;
+ coverage = value;
return (data+coverage).intersects (glyphs);
}
-static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
{
unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
intersected_glyphs->add (g);
}
-static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+using intersected_class_cache_t = hb_hashmap_t<unsigned, hb_set_t>;
+
+static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
- class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
+
+ intersected_class_cache_t *map = (intersected_class_cache_t *) cache;
+
+ hb_set_t *cached_v;
+ if (map->has (value, &cached_v))
+ {
+ intersected_glyphs->union_ (*cached_v);
+ return;
+ }
+
+ hb_set_t v;
+ class_def.intersected_class_glyphs (glyphs, value, &v);
+
+ intersected_glyphs->union_ (v);
+
+ map->set (value, std::move (v));
}
-static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
{
Offset16To<Coverage> coverage;
coverage = value;
- (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
+ (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
}
+template <typename HBUINT>
static inline bool array_is_subset_of (const hb_set_t *glyphs,
unsigned int count,
- const HBUINT16 values[],
+ const HBUINT values[],
intersects_func_t intersects_func,
- const void *intersects_data)
+ const void *intersects_data,
+ void *cache)
{
- for (const HBUINT16 &_ : + hb_iter (values, count))
- if (!intersects_func (glyphs, _, intersects_data)) return false;
+ for (const auto &_ : + hb_iter (values, count))
+ if (!intersects_func (glyphs, _, intersects_data, cache)) return false;
return true;
}
-static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
{
glyphs->add (value);
}
-static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
class_def.collect_class (glyphs, value);
}
-static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
{
- const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+ Offset16To<Coverage> coverage;
+ coverage = value;
(data+coverage).collect_coverage (glyphs);
}
+template <typename HBUINT>
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
hb_set_t *glyphs,
unsigned int count,
- const HBUINT16 values[],
+ const HBUINT values[],
collect_glyphs_func_t collect_func,
const void *collect_data)
{
return
+ hb_iter (values, count)
- | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
+ | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
;
}
-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, unsigned 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, unsigned 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, unsigned value, const void *data)
{
- const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
- return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
+ 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, unsigned value, const void *data)
+{
+ Offset16To<Coverage> coverage;
+ coverage = value;
+ return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
}
+template <typename HBUINT>
static inline bool would_match_input (hb_would_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
match_func_t match_func,
const void *match_data)
{
@@ -923,17 +1171,22 @@ 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;
}
+template <typename HBUINT>
static inline bool match_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
match_func_t match_func,
const void *match_data,
- unsigned int *end_offset,
+ unsigned int *end_position,
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
unsigned int *p_total_component_count = nullptr)
{
@@ -945,7 +1198,8 @@ static inline bool match_input (hb_ot_apply_context_t *c,
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, count - 1);
- skippy_iter.set_match_func (match_func, match_data, input);
+ skippy_iter.set_match_func (match_func, match_data);
+ skippy_iter.set_glyph_data (input);
/*
* This is perhaps the trickiest part of OpenType... Remarks:
@@ -986,7 +1240,12 @@ static inline bool match_input (hb_ot_apply_context_t *c,
match_positions[0] = buffer->idx;
for (unsigned int i = 1; i < count; i++)
{
- if (!skippy_iter.next ()) return_trace (false);
+ unsigned unsafe_to;
+ if (!skippy_iter.next (&unsafe_to))
+ {
+ *end_position = unsafe_to;
+ return_trace (false);
+ }
match_positions[i] = skippy_iter.idx;
@@ -1040,7 +1299,7 @@ static inline bool match_input (hb_ot_apply_context_t *c,
total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
}
- *end_offset = skippy_iter.idx - buffer->idx + 1;
+ *end_position = skippy_iter.idx + 1;
if (p_total_component_count)
*p_total_component_count = total_component_count;
@@ -1050,7 +1309,7 @@ static inline bool match_input (hb_ot_apply_context_t *c,
static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
- unsigned int match_length,
+ unsigned int match_end,
hb_codepoint_t lig_glyph,
unsigned int total_component_count)
{
@@ -1058,7 +1317,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
- buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
+ buffer->merge_clusters (buffer->idx, match_end);
/* - If a base and one or more marks ligate, consider that as a base, NOT
* ligature, such that all following marks can still attach to it.
@@ -1161,9 +1420,10 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
return_trace (true);
}
+template <typename HBUINT>
static inline bool match_backtrack (hb_ot_apply_context_t *c,
unsigned int count,
- const HBUINT16 backtrack[],
+ const HBUINT backtrack[],
match_func_t match_func,
const void *match_data,
unsigned int *match_start)
@@ -1172,37 +1432,50 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
skippy_iter.reset (c->buffer->backtrack_len (), count);
- skippy_iter.set_match_func (match_func, match_data, backtrack);
+ skippy_iter.set_match_func (match_func, match_data);
+ skippy_iter.set_glyph_data (backtrack);
for (unsigned int i = 0; i < count; i++)
- if (!skippy_iter.prev ())
+ {
+ unsigned unsafe_from;
+ if (!skippy_iter.prev (&unsafe_from))
+ {
+ *match_start = unsafe_from;
return_trace (false);
+ }
+ }
*match_start = skippy_iter.idx;
-
return_trace (true);
}
+template <typename HBUINT>
static inline bool match_lookahead (hb_ot_apply_context_t *c,
unsigned int count,
- const HBUINT16 lookahead[],
+ const HBUINT lookahead[],
match_func_t match_func,
const void *match_data,
- unsigned int offset,
+ unsigned int start_index,
unsigned int *end_index)
{
TRACE_APPLY (nullptr);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
- skippy_iter.reset (c->buffer->idx + offset - 1, count);
- skippy_iter.set_match_func (match_func, match_data, lookahead);
+ skippy_iter.reset (start_index - 1, count);
+ skippy_iter.set_match_func (match_func, match_data);
+ skippy_iter.set_glyph_data (lookahead);
for (unsigned int i = 0; i < count; i++)
- if (!skippy_iter.next ())
+ {
+ unsigned unsafe_to;
+ if (!skippy_iter.next (&unsafe_to))
+ {
+ *end_index = unsafe_to;
return_trace (false);
+ }
+ }
*end_index = skippy_iter.idx + 1;
-
return_trace (true);
}
@@ -1254,14 +1527,16 @@ static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
+template <typename HBUINT>
static void context_closure_recurse_lookups (hb_closure_context_t *c,
- unsigned inputCount, const HBUINT16 input[],
+ unsigned inputCount, const HBUINT input[],
unsigned lookupCount,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
unsigned value,
ContextFormat context_format,
const void *data,
- intersected_glyphs_func_t intersected_glyphs_func)
+ intersected_glyphs_func_t intersected_glyphs_func,
+ void *cache)
{
hb_set_t *covered_seq_indicies = hb_set_create ();
for (unsigned int i = 0; i < lookupCount; i++)
@@ -1269,22 +1544,23 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
unsigned seqIndex = lookupRecord[i].sequenceIndex;
if (seqIndex >= inputCount) continue;
- hb_set_t *pos_glyphs = nullptr;
+ bool has_pos_glyphs = false;
+ hb_set_t pos_glyphs;
- if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex))
+ if (!hb_set_has (covered_seq_indicies, seqIndex))
{
- pos_glyphs = hb_set_create ();
+ has_pos_glyphs = true;
if (seqIndex == 0)
{
switch (context_format) {
case ContextFormat::SimpleContext:
- pos_glyphs->add (value);
+ pos_glyphs.add (value);
break;
case ContextFormat::ClassBasedContext:
- intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs);
+ intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache);
break;
case ContextFormat::CoverageBasedContext:
- hb_set_set (pos_glyphs, c->cur_intersected_glyphs);
+ pos_glyphs.set (c->parent_active_glyphs ());
break;
}
}
@@ -1298,13 +1574,16 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
input_value = input[seqIndex - 1];
}
- intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs);
+ intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache);
}
}
- hb_set_add (covered_seq_indicies, seqIndex);
- if (pos_glyphs)
- c->push_cur_active_glyphs (pos_glyphs);
+ covered_seq_indicies->add (seqIndex);
+ if (has_pos_glyphs) {
+ c->push_cur_active_glyphs () = std::move (pos_glyphs);
+ } else {
+ c->push_cur_active_glyphs ().set (*c->glyphs);
+ }
unsigned endIndex = inputCount;
if (context_format == ContextFormat::CoverageBasedContext)
@@ -1312,10 +1591,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
- if (pos_glyphs) {
- c->pop_cur_done_glyphs ();
- hb_set_destroy (pos_glyphs);
- }
+ c->pop_cur_done_glyphs ();
}
hb_set_destroy (covered_seq_indicies);
@@ -1330,15 +1606,13 @@ static inline void recurse_lookups (context_t *c,
c->recurse (lookupRecord[i].lookupListIndex);
}
-static inline bool apply_lookup (hb_ot_apply_context_t *c,
+static inline void apply_lookup (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
- unsigned int match_length)
+ unsigned int match_end)
{
- TRACE_APPLY (nullptr);
-
hb_buffer_t *buffer = c->buffer;
int end;
@@ -1346,7 +1620,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
* Adjust. */
{
unsigned int bl = buffer->backtrack_len ();
- end = bl + match_length;
+ end = bl + match_end - buffer->idx;
int delta = bl - buffer->idx;
/* Convert positions to new indexing. */
@@ -1360,9 +1634,10 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
if (idx >= count)
continue;
- /* Don't recurse to ourself at same position.
- * Note that this test is too naive, it doesn't catch longer loops. */
- if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
+ unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+
+ /* This can happen if earlier recursed lookups deleted many entries. */
+ if (unlikely (match_positions[idx] >= orig_len))
continue;
if (unlikely (!buffer->move_to (match_positions[idx])))
@@ -1371,10 +1646,28 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
if (unlikely (buffer->max_ops <= 0))
break;
- unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ if (buffer->have_output)
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "recursing to lookup %u at %d",
+ (unsigned) lookupRecord[i].lookupListIndex,
+ buffer->idx);
+ }
+
if (!c->recurse (lookupRecord[i].lookupListIndex))
continue;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ if (buffer->have_output)
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "recursed to lookup %u",
+ (unsigned) lookupRecord[i].lookupListIndex);
+ }
+
unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
int delta = new_len - orig_len;
@@ -1397,25 +1690,27 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
* NOT the one after it.
*
* - If buffer length was decreased by n, it does not necessarily
- * mean that n match positions where removed, as there might
- * have been marks and default-ignorables in the sequence. We
- * should instead drop match positions between current-position
- * and current-position + n instead. Though, am not sure which
- * one is better. Both cases have valid uses. Sigh.
+ * mean that n match positions where removed, as there recursed-to
+ * lookup might had a different LookupFlag. Here's a constructed
+ * case of that:
+ * https://github.com/harfbuzz/harfbuzz/discussions/3538
*
* It should be possible to construct tests for both of these cases.
*/
end += delta;
- if (end <= int (match_positions[idx]))
+ if (end < int (match_positions[idx]))
{
/* End might end up being smaller than match_positions[idx] if the recursed
- * lookup ended up removing many items, more than we have had matched.
- * Just never rewind end back and get out of here.
- * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
+ * lookup ended up removing many items.
+ * Just never rewind end beyond start of current position, since that is
+ * not possible in the recursed lookup. Also adjust delta as such.
+ *
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
+ * https://github.com/harfbuzz/harfbuzz/issues/1611
+ */
+ delta += match_positions[idx] - end;
end = match_positions[idx];
- /* There can't be any further changes. */
- break;
}
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@@ -1427,7 +1722,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
}
else
{
- /* NOTE: delta is negative. */
+ /* NOTE: delta is non-positive. */
delta = hb_max (delta, (int) next - (int) count);
next -= delta;
}
@@ -1448,8 +1743,6 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
}
(void) buffer->move_to (end);
-
- return_trace (true);
}
@@ -1461,6 +1754,8 @@ struct ContextClosureLookupContext
ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data;
+ void *intersects_cache;
+ void *intersected_glyphs_cache;
};
struct ContextCollectGlyphsLookupContext
@@ -1475,19 +1770,23 @@ struct ContextApplyLookupContext
const void *match_data;
};
+template <typename HBUINT>
static inline bool context_intersects (const hb_set_t *glyphs,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
ContextClosureLookupContext &lookup_context)
{
return array_is_subset_of (glyphs,
inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data);
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data,
+ lookup_context.intersects_cache);
}
+template <typename HBUINT>
static inline void context_closure_lookup (hb_closure_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[],
unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
@@ -1502,12 +1801,14 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
value,
lookup_context.context_format,
lookup_context.intersects_data,
- lookup_context.funcs.intersected_glyphs);
+ lookup_context.funcs.intersected_glyphs,
+ lookup_context.intersected_glyphs_cache);
}
+template <typename HBUINT>
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[],
ContextCollectGlyphsLookupContext &lookup_context)
@@ -1519,37 +1820,49 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c
lookupCount, lookupRecord);
}
+template <typename HBUINT>
static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount HB_UNUSED,
const LookupRecord lookupRecord[] HB_UNUSED,
- ContextApplyLookupContext &lookup_context)
+ const ContextApplyLookupContext &lookup_context)
{
return would_match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data);
}
+
+template <typename HBUINT>
static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[],
- ContextApplyLookupContext &lookup_context)
-{
- unsigned int match_length = 0;
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
- return match_input (c,
- inputCount, input,
- lookup_context.funcs.match, lookup_context.match_data,
- &match_length, match_positions)
- && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
- apply_lookup (c,
- inputCount, match_positions,
- lookupCount, lookupRecord,
- match_length));
+ const ContextApplyLookupContext &lookup_context)
+{
+ unsigned match_end = 0;
+ unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+ if (match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data,
+ &match_end, match_positions))
+ {
+ c->buffer->unsafe_to_break (c->buffer->idx, match_end);
+ apply_lookup (c,
+ inputCount, match_positions,
+ lookupCount, lookupRecord,
+ match_end);
+ return true;
+ }
+ else
+ {
+ c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
+ return false;
+ }
}
+template <typename Types>
struct Rule
{
bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
@@ -1563,8 +1876,8 @@ struct Rule
{
if (unlikely (c->lookup_limit_exceeded ())) return;
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
context_closure_lookup (c,
inputCount, inputZ.arrayZ,
lookupCount, lookupRecord.arrayZ,
@@ -1577,16 +1890,16 @@ struct Rule
if (unlikely (c->lookup_limit_exceeded ())) return;
if (!intersects (c->glyphs, lookup_context)) return;
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array (inputCount ? inputCount - 1 : 0));
recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
}
void collect_glyphs (hb_collect_glyphs_context_t *c,
ContextCollectGlyphsLookupContext &lookup_context) const
{
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array (inputCount ? inputCount - 1 : 0));
context_collect_glyphs_lookup (c,
inputCount, inputZ.arrayZ,
lookupCount, lookupRecord.arrayZ,
@@ -1594,10 +1907,10 @@ struct Rule
}
bool would_apply (hb_would_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array (inputCount ? inputCount - 1 : 0));
return context_would_apply_lookup (c,
inputCount, inputZ.arrayZ,
lookupCount, lookupRecord.arrayZ,
@@ -1605,11 +1918,11 @@ struct Rule
}
bool apply (hb_ot_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array (inputCount ? inputCount - 1 : 0));
return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
}
@@ -1622,7 +1935,7 @@ struct Rule
if (unlikely (!c->extend_min (out))) return_trace (false);
out->inputCount = inputCount;
- const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+ const auto input = inputZ.as_array (inputCount - 1);
for (const auto org : input)
{
HBUINT16 d;
@@ -1630,8 +1943,8 @@ struct Rule
c->copy (d);
}
- const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
- (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+ const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+ (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
@@ -1642,9 +1955,8 @@ struct Rule
const hb_map_t *klass_map = nullptr) const
{
TRACE_SUBSET (this);
-
- const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
- if (!input.length) return_trace (false);
+ if (unlikely (!inputCount)) return_trace (false);
+ const auto input = inputZ.as_array (inputCount - 1);
const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
if (!hb_all (input, mapping)) return_trace (false);
@@ -1667,7 +1979,7 @@ struct Rule
* glyph sequence--includes the first
* glyph */
HBUINT16 lookupCount; /* Number of LookupRecords */
- UnsizedArrayOf<HBUINT16>
+ UnsizedArrayOf<typename Types::HBUINT>
inputZ; /* Array of match inputs--start with
* second glyph */
/*UnsizedArrayOf<LookupRecord>
@@ -1677,8 +1989,11 @@ struct Rule
DEFINE_SIZE_ARRAY (4, inputZ);
};
+template <typename Types>
struct RuleSet
{
+ using Rule = OT::Rule<Types>;
+
bool intersects (const hb_set_t *glyphs,
ContextClosureLookupContext &lookup_context) const
{
@@ -1723,7 +2038,7 @@ struct RuleSet
}
bool would_apply (hb_would_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
return
+ hb_iter (rule)
@@ -1734,7 +2049,7 @@ struct RuleSet
}
bool apply (hb_ot_apply_context_t *c,
- ContextApplyLookupContext &lookup_context) const
+ const ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
return_trace (
@@ -1791,8 +2106,11 @@ struct RuleSet
};
-struct ContextFormat1
+template <typename Types>
+struct ContextFormat1_4
{
+ using RuleSet = OT::RuleSet<Types>;
+
bool intersects (const hb_set_t *glyphs) const
{
struct ContextClosureLookupContext lookup_context = {
@@ -1816,8 +2134,8 @@ struct ContextFormat1
void closure (hb_closure_context_t *c) const
{
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
struct ContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -1826,16 +2144,20 @@ struct ContextFormat1
};
+ hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
- | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_filter ([&] (hb_codepoint_t _) {
+ return c->previous_parent_active_glyphs ().has (_);
+ }, hb_first)
| hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
| hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
;
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph, intersected_glyph},
+ {intersects_glyph, nullptr},
ContextFormat::SimpleContext,
nullptr
};
@@ -1924,19 +2246,22 @@ struct ContextFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
+ typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- Array16OfOffset16To<RuleSet>
+ Array16Of<typename Types::template OffsetTo<RuleSet>>
ruleSet; /* Array of RuleSet tables
* ordered by Coverage Index */
public:
- DEFINE_SIZE_ARRAY (6, ruleSet);
+ DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
};
-struct ContextFormat2
+template <typename Types>
+struct ContextFormat2_5
{
+ using RuleSet = OT::RuleSet<SmallTypes>;
+
bool intersects (const hb_set_t *glyphs) const
{
if (!(this+coverage).intersects (glyphs))
@@ -1944,14 +2269,16 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache
};
hb_set_t retained_coverage_glyphs;
- (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+ (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
hb_set_t coverage_glyph_classes;
class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -1977,28 +2304,34 @@ struct ContextFormat2
if (!(this+coverage).intersects (c->glyphs))
return;
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+ cur_active_glyphs);
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
+ intersected_class_cache_t intersected_cache;
struct ContextClosureLookupContext lookup_context = {
{intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache,
+ &intersected_cache
};
- return
+ hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _)
- { return class_def.intersects_class (c->cur_intersected_glyphs, _); },
+ { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
hb_first)
- | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
+ | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
{
const RuleSet& rule_set = this+_.second;
rule_set.closure (c, _.first, lookup_context);
})
;
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -2008,10 +2341,12 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef;
+ hb_map_t cache;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
- &class_def
+ &class_def,
+ &cache
};
+ hb_iter (ruleSet)
@@ -2056,19 +2391,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));
}
@@ -2086,7 +2456,7 @@ struct ContextFormat2
const hb_set_t* glyphset = c->plan->glyphset_gsub ();
hb_set_t retained_coverage_glyphs;
- (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+ (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
hb_set_t coverage_glyph_classes;
(this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -2094,6 +2464,7 @@ struct ContextFormat2
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
bool ret = true;
int non_zero_index = -1, index = 0;
+ auto snapshot = c->serializer->snapshot();
for (const auto& _ : + hb_enumerate (ruleSet)
| hb_filter (klass_map, hb_first))
{
@@ -2105,8 +2476,10 @@ struct ContextFormat2
}
if (coverage_glyph_classes.has (_.first) &&
- o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+ o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) {
non_zero_index = index;
+ snapshot = c->serializer->snapshot();
+ }
index++;
}
@@ -2120,6 +2493,7 @@ struct ContextFormat2
out->ruleSet.pop ();
index--;
}
+ c->serializer->revert (snapshot);
return_trace (bool (out->ruleSet));
}
@@ -2132,29 +2506,31 @@ struct ContextFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- Offset16To<Coverage>
+ typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- Offset16To<ClassDef>
+ typename Types::template OffsetTo<ClassDef>
classDef; /* Offset to glyph ClassDef table--from
* beginning of table */
- Array16OfOffset16To<RuleSet>
+ Array16Of<typename Types::template OffsetTo<RuleSet>>
ruleSet; /* Array of RuleSet tables
* ordered by class */
public:
- DEFINE_SIZE_ARRAY (8, ruleSet);
+ DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
};
struct ContextFormat3
{
+ using RuleSet = OT::RuleSet<SmallTypes>;
+
bool intersects (const hb_set_t *glyphs) const
{
if (!(this+coverageZ[0]).intersects (glyphs))
return false;
struct ContextClosureLookupContext lookup_context = {
- {intersects_coverage, intersected_coverage_glyphs},
+ {intersects_coverage, nullptr},
ContextFormat::CoverageBasedContext,
this
};
@@ -2171,8 +2547,10 @@ struct ContextFormat3
if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+ cur_active_glyphs);
+
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextClosureLookupContext lookup_context = {
@@ -2184,6 +2562,8 @@ struct ContextFormat3
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
lookupCount, lookupRecord,
0, lookup_context);
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -2260,7 +2640,7 @@ struct ContextFormat3
if (!o->serialize_subset (c, offset, this)) return_trace (false);
}
- const UnsizedArrayOf<LookupRecord>& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
+ const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
@@ -2307,16 +2687,24 @@ struct Context
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+ case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+ case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
default:return_trace (c->default_return_value ());
}
}
protected:
union {
- HBUINT16 format; /* Format identifier */
- ContextFormat1 format1;
- ContextFormat2 format2;
- ContextFormat3 format3;
+ HBUINT16 format; /* Format identifier */
+ ContextFormat1_4<SmallTypes> format1;
+ ContextFormat2_5<SmallTypes> format2;
+ ContextFormat3 format3;
+#ifndef HB_NO_BEYOND_64K
+ ContextFormat1_4<MediumTypes> format4;
+ ContextFormat2_5<MediumTypes> format5;
+#endif
} u;
};
@@ -2328,6 +2716,8 @@ struct ChainContextClosureLookupContext
ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data[3];
+ void *intersects_cache[3];
+ void *intersected_glyphs_cache;
};
struct ChainContextCollectGlyphsLookupContext
@@ -2338,37 +2728,45 @@ struct ChainContextCollectGlyphsLookupContext
struct ChainContextApplyLookupContext
{
- ContextApplyFuncs funcs;
+ ChainContextApplyFuncs funcs;
const void *match_data[3];
};
+template <typename HBUINT>
static inline bool chain_context_intersects (const hb_set_t *glyphs,
unsigned int backtrackCount,
- const HBUINT16 backtrack[],
+ const HBUINT backtrack[],
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookaheadCount,
- const HBUINT16 lookahead[],
+ const HBUINT lookahead[],
ChainContextClosureLookupContext &lookup_context)
{
return array_is_subset_of (glyphs,
backtrackCount, backtrack,
- lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[0],
+ lookup_context.intersects_cache[0])
&& array_is_subset_of (glyphs,
inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[1],
+ lookup_context.intersects_cache[1])
&& array_is_subset_of (glyphs,
lookaheadCount, lookahead,
- lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+ lookup_context.funcs.intersects,
+ lookup_context.intersects_data[2],
+ lookup_context.intersects_cache[2]);
}
+template <typename HBUINT>
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
unsigned int backtrackCount,
- const HBUINT16 backtrack[],
+ const HBUINT backtrack[],
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookaheadCount,
- const HBUINT16 lookahead[],
+ const HBUINT lookahead[],
unsigned int lookupCount,
const LookupRecord lookupRecord[],
unsigned value,
@@ -2385,16 +2783,18 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
value,
lookup_context.context_format,
lookup_context.intersects_data[1],
- lookup_context.funcs.intersected_glyphs);
+ lookup_context.funcs.intersected_glyphs,
+ lookup_context.intersected_glyphs_cache);
}
+template <typename HBUINT>
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
unsigned int backtrackCount,
- const HBUINT16 backtrack[],
+ const HBUINT backtrack[],
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookaheadCount,
- const HBUINT16 lookahead[],
+ const HBUINT lookahead[],
unsigned int lookupCount,
const LookupRecord lookupRecord[],
ChainContextCollectGlyphsLookupContext &lookup_context)
@@ -2412,61 +2812,77 @@ static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_contex
lookupCount, lookupRecord);
}
+template <typename HBUINT>
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
unsigned int backtrackCount,
- const HBUINT16 backtrack[] HB_UNUSED,
+ const HBUINT backtrack[] HB_UNUSED,
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookaheadCount,
- const HBUINT16 lookahead[] HB_UNUSED,
+ const HBUINT lookahead[] HB_UNUSED,
unsigned int lookupCount HB_UNUSED,
const LookupRecord lookupRecord[] HB_UNUSED,
- ChainContextApplyLookupContext &lookup_context)
+ const ChainContextApplyLookupContext &lookup_context)
{
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]);
}
+template <typename HBUINT>
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
unsigned int backtrackCount,
- const HBUINT16 backtrack[],
+ const HBUINT backtrack[],
unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT16 input[], /* Array of input values--start with second glyph */
+ const HBUINT input[], /* Array of input values--start with second glyph */
unsigned int lookaheadCount,
- const HBUINT16 lookahead[],
+ const HBUINT lookahead[],
unsigned int lookupCount,
const LookupRecord lookupRecord[],
- ChainContextApplyLookupContext &lookup_context)
-{
- unsigned int start_index = 0, match_length = 0, end_index = 0;
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
- return match_input (c,
- inputCount, input,
- lookup_context.funcs.match, lookup_context.match_data[1],
- &match_length, match_positions)
- && match_backtrack (c,
- backtrackCount, backtrack,
- lookup_context.funcs.match, lookup_context.match_data[0],
- &start_index)
- && match_lookahead (c,
- lookaheadCount, lookahead,
- lookup_context.funcs.match, lookup_context.match_data[2],
- match_length, &end_index)
- && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
- apply_lookup (c,
- inputCount, match_positions,
- lookupCount, lookupRecord,
- match_length));
+ const ChainContextApplyLookupContext &lookup_context)
+{
+ unsigned end_index = c->buffer->idx;
+ unsigned match_end = 0;
+ unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+ if (!(match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match[1], lookup_context.match_data[1],
+ &match_end, match_positions) && (end_index = match_end)
+ && match_lookahead (c,
+ lookaheadCount, lookahead,
+ lookup_context.funcs.match[2], lookup_context.match_data[2],
+ match_end, &end_index)))
+ {
+ c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
+ return false;
+ }
+
+ unsigned start_index = c->buffer->out_len;
+ if (!match_backtrack (c,
+ backtrackCount, backtrack,
+ lookup_context.funcs.match[0], lookup_context.match_data[0],
+ &start_index))
+ {
+ c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
+ return false;
+ }
+
+ c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+ apply_lookup (c,
+ inputCount, match_positions,
+ lookupCount, lookupRecord,
+ match_end);
+ return true;
}
+template <typename Types>
struct ChainRule
{
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
return chain_context_intersects (glyphs,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2479,9 +2895,9 @@ struct ChainRule
{
if (unlikely (c->lookup_limit_exceeded ())) return;
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
chain_context_closure_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2497,18 +2913,18 @@ struct ChainRule
if (unlikely (c->lookup_limit_exceeded ())) return;
if (!intersects (c->glyphs, lookup_context)) return;
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
void collect_glyphs (hb_collect_glyphs_context_t *c,
ChainContextCollectGlyphsLookupContext &lookup_context) const
{
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
chain_context_collect_glyphs_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2518,11 +2934,11 @@ struct ChainRule
}
bool would_apply (hb_would_apply_context_t *c,
- ChainContextApplyLookupContext &lookup_context) const
+ const ChainContextApplyLookupContext &lookup_context) const
{
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return chain_context_would_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2530,12 +2946,13 @@ struct ChainRule
lookup.arrayZ, lookup_context);
}
- bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool apply (hb_ot_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return_trace (chain_context_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2568,22 +2985,22 @@ struct ChainRule
serialize_array (c, backtrack.len, + backtrack.iter ()
| hb_map (mapping));
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (input_map) mapping = input_map;
serialize_array (c, input.lenP1, + input.iter ()
| hb_map (mapping));
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (lookahead_map) mapping = lookahead_map;
serialize_array (c, lookahead.len, + lookahead.iter ()
| hb_map (mapping));
- const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
- HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+ HBUINT16* lookupCount = c->embed (&(lookup.len));
if (!lookupCount) return_trace (false);
- unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (), lookup_map);
+ unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -2595,8 +3012,8 @@ struct ChainRule
{
TRACE_SUBSET (this);
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (!backtrack_map)
{
@@ -2625,23 +3042,23 @@ struct ChainRule
{
TRACE_SANITIZE (this);
if (!backtrack.sanitize (c)) return_trace (false);
- const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (!input.sanitize (c)) return_trace (false);
- const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (!lookahead.sanitize (c)) return_trace (false);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return_trace (lookup.sanitize (c));
}
protected:
- Array16Of<HBUINT16>
+ Array16Of<typename Types::HBUINT>
backtrack; /* Array of backtracking values
* (to be matched before the input
* sequence) */
- HeadlessArrayOf<HBUINT16>
+ HeadlessArrayOf<typename Types::HBUINT>
inputX; /* Array of input values (start with
* second glyph) */
- Array16Of<HBUINT16>
+ Array16Of<typename Types::HBUINT>
lookaheadX; /* Array of lookahead values's (to be
* matched after the input sequence) */
Array16Of<LookupRecord>
@@ -2651,8 +3068,11 @@ struct ChainRule
DEFINE_SIZE_MIN (8);
};
+template <typename Types>
struct ChainRuleSet
{
+ using ChainRule = OT::ChainRule<Types>;
+
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{
return
@@ -2693,7 +3113,8 @@ struct ChainRuleSet
;
}
- bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool would_apply (hb_would_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
return
+ hb_iter (rule)
@@ -2703,7 +3124,8 @@ struct ChainRuleSet
;
}
- bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ bool apply (hb_ot_apply_context_t *c,
+ const ChainContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
return_trace (
@@ -2765,8 +3187,11 @@ struct ChainRuleSet
DEFINE_SIZE_ARRAY (2, rule);
};
-struct ChainContextFormat1
+template <typename Types>
+struct ChainContextFormat1_4
{
+ using ChainRuleSet = OT::ChainRuleSet<Types>;
+
bool intersects (const hb_set_t *glyphs) const
{
struct ChainContextClosureLookupContext lookup_context = {
@@ -2790,8 +3215,9 @@ struct ChainContextFormat1
void closure (hb_closure_context_t *c) const
{
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+ cur_active_glyphs);
struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -2800,16 +3226,20 @@ struct ChainContextFormat1
};
+ hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
- | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_filter ([&] (hb_codepoint_t _) {
+ return c->previous_parent_active_glyphs ().has (_);
+ }, hb_first)
| hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
| hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
;
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph, intersected_glyph},
+ {intersects_glyph, nullptr},
ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr}
};
@@ -2843,7 +3273,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);
@@ -2859,7 +3289,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));
@@ -2897,18 +3327,21 @@ struct ChainContextFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- Offset16To<Coverage>
+ typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- Array16OfOffset16To<ChainRuleSet>
+ Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
ruleSet; /* Array of ChainRuleSet tables
* ordered by Coverage Index */
public:
- DEFINE_SIZE_ARRAY (6, ruleSet);
+ DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
};
-struct ChainContextFormat2
+template <typename Types>
+struct ChainContextFormat2_5
{
+ using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
+
bool intersects (const hb_set_t *glyphs) const
{
if (!(this+coverage).intersects (glyphs))
@@ -2918,16 +3351,18 @@ struct ChainContextFormat2
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]}
};
hb_set_t retained_coverage_glyphs;
- (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+ (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
hb_set_t coverage_glyph_classes;
input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -2952,32 +3387,39 @@ struct ChainContextFormat2
if (!(this+coverage).intersects (c->glyphs))
return;
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+ cur_active_glyphs);
+
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
+ intersected_class_cache_t intersected_cache;
struct ChainContextClosureLookupContext lookup_context = {
{intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]},
+ &intersected_cache
};
- return
+ hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _)
- { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); },
+ { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
hb_first)
- | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
+ | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
{
const ChainRuleSet& chainrule_set = this+_.second;
chainrule_set.closure (c, _.first, lookup_context);
})
;
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -2989,12 +3431,14 @@ struct ChainContextFormat2
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+ hb_map_t caches[3] = {};
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class, intersected_class_glyphs},
+ {intersects_class, nullptr},
ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
- &lookahead_class_def}
+ &lookahead_class_def},
+ {&caches[0], &caches[1], &caches[2]}
};
+ hb_iter (ruleSet)
@@ -3040,7 +3484,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}
@@ -3050,7 +3494,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);
@@ -3060,14 +3530,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_5 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));
}
@@ -3095,7 +3578,7 @@ struct ChainContextFormat2
const hb_set_t* glyphset = c->plan->glyphset_gsub ();
hb_set_t retained_coverage_glyphs;
- (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+ (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
hb_set_t coverage_glyph_classes;
(this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -3150,40 +3633,42 @@ struct ChainContextFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- Offset16To<Coverage>
+ typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- Offset16To<ClassDef>
+ typename Types::template OffsetTo<ClassDef>
backtrackClassDef; /* Offset to glyph ClassDef table
* containing backtrack sequence
* data--from beginning of table */
- Offset16To<ClassDef>
+ typename Types::template OffsetTo<ClassDef>
inputClassDef; /* Offset to glyph ClassDef
* table containing input sequence
* data--from beginning of table */
- Offset16To<ClassDef>
+ typename Types::template OffsetTo<ClassDef>
lookaheadClassDef; /* Offset to glyph ClassDef table
* containing lookahead sequence
* data--from beginning of table */
- Array16OfOffset16To<ChainRuleSet>
+ Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
ruleSet; /* Array of ChainRuleSet tables
* ordered by class */
public:
- DEFINE_SIZE_ARRAY (12, ruleSet);
+ DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
};
struct ChainContextFormat3
{
+ using RuleSet = OT::RuleSet<SmallTypes>;
+
bool intersects (const hb_set_t *glyphs) const
{
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (!(this+input[0]).intersects (glyphs))
return false;
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_coverage, intersected_coverage_glyphs},
+ {intersects_coverage, nullptr},
ContextFormat::CoverageBasedContext,
{this, this, this}
};
@@ -3199,16 +3684,18 @@ struct ChainContextFormat3
void closure (hb_closure_context_t *c) const
{
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (!(this+input[0]).intersects (c->glyphs))
return;
- c->cur_intersected_glyphs->clear ();
- get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+ hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+ cur_active_glyphs);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
struct ChainContextClosureLookupContext lookup_context = {
{intersects_coverage, intersected_coverage_glyphs},
ContextFormat::CoverageBasedContext,
@@ -3220,6 +3707,8 @@ struct ChainContextFormat3
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
lookup.len, lookup.arrayZ,
0, lookup_context);
+
+ c->pop_cur_done_glyphs ();
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -3227,9 +3716,9 @@ struct ChainContextFormat3
if (!intersects (c->glyphs))
return;
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
@@ -3237,12 +3726,13 @@ struct ChainContextFormat3
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
(this+input[0]).collect_coverage (c->input);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+
struct ChainContextCollectGlyphsLookupContext lookup_context = {
{collect_coverage},
{this, this, this}
@@ -3257,11 +3747,11 @@ struct ChainContextFormat3
bool would_apply (hb_would_apply_context_t *c) const
{
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
- {match_coverage},
+ {{match_coverage, match_coverage, match_coverage}},
{this, this, this}
};
return chain_context_would_apply_lookup (c,
@@ -3273,22 +3763,22 @@ struct ChainContextFormat3
const Coverage &get_coverage () const
{
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
return this+input[0];
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
- {match_coverage},
+ {{match_coverage, match_coverage, match_coverage}},
{this, this, this}
};
return_trace (chain_context_apply_lookup (c,
@@ -3328,21 +3818,21 @@ struct ChainContextFormat3
if (!serialize_coverage_offsets (c, backtrack.iter (), this))
return_trace (false);
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (!serialize_coverage_offsets (c, input.iter (), this))
return_trace (false);
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (!serialize_coverage_offsets (c, lookahead.iter (), this))
return_trace (false);
- const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
- HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookupRecord.len);
+ HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
if (!lookupCount) return_trace (false);
- unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (), lookup_map);
+ unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -3350,12 +3840,12 @@ struct ChainContextFormat3
{
TRACE_SANITIZE (this);
if (!backtrack.sanitize (c, this)) return_trace (false);
- const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (!input.sanitize (c, this)) return_trace (false);
if (!input.len) return_trace (false); /* To be consistent with Context. */
- const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (!lookahead.sanitize (c, this)) return_trace (false);
- const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+ const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return_trace (lookup.sanitize (c));
}
@@ -3391,16 +3881,24 @@ struct ChainContext
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+ case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+ case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
default:return_trace (c->default_return_value ());
}
}
protected:
union {
- HBUINT16 format; /* Format identifier */
- ChainContextFormat1 format1;
- ChainContextFormat2 format2;
- ChainContextFormat3 format3;
+ HBUINT16 format; /* Format identifier */
+ ChainContextFormat1_4<SmallTypes> format1;
+ ChainContextFormat2_5<SmallTypes> format2;
+ ChainContextFormat3 format3;
+#ifndef HB_NO_BEYOND_64K
+ ChainContextFormat1_4<MediumTypes> format4;
+ ChainContextFormat2_5<MediumTypes> format5;
+#endif
} u;
};
@@ -3521,64 +4019,282 @@ struct hb_ot_layout_lookup_accelerator_t
template <typename TLookup>
void init (const TLookup &lookup)
{
- digest.init ();
- lookup.collect_coverage (&digest);
-
subtables.init ();
- OT::hb_get_subtables_context_t c_get_subtables (subtables);
- lookup.dispatch (&c_get_subtables);
+ hb_accelerate_subtables_context_t c_accelerate_subtables (subtables);
+ lookup.dispatch (&c_accelerate_subtables);
+
+ digest.init ();
+ for (auto& subtable : hb_iter (subtables))
+ digest.add (subtable.digest);
+
+#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)
+ {
+ return
+ + hb_iter (subtables)
+ | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
+ | hb_any
+ ;
+ }
+ else
+#endif
+ {
+ return
+ + hb_iter (subtables)
+ | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
+ | hb_any
+ ;
+ }
return false;
}
- private:
+ bool cache_enter (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 (hb_ot_apply_context_t *c) const
+ {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ subtables[cache_user_idx].cache_leave (c);
+#endif
+ }
+
+
hb_set_digest_t digest;
- hb_get_subtables_context_t::array_t subtables;
+ private:
+ hb_accelerate_subtables_context_t::array_t subtables;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+ unsigned cache_user_idx = (unsigned) -1;
+#endif
+};
+
+template <typename Types>
+struct GSUBGPOSVersion1_2
+{
+ friend struct GSUBGPOS;
+
+ protected:
+ FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
+ * to 0x00010000u */
+ typename Types:: template OffsetTo<ScriptList>
+ scriptList; /* ScriptList table */
+ typename Types::template OffsetTo<FeatureList>
+ featureList; /* FeatureList table */
+ typename Types::template OffsetTo<LookupList<Types>>
+ lookupList; /* LookupList table */
+ Offset32To<FeatureVariations>
+ featureVars; /* Offset to Feature Variations
+ table--from beginning of table
+ * (may be NULL). Introduced
+ * in version 0x00010001. */
+ public:
+ DEFINE_SIZE_MIN (4 + 3 * Types::size);
+
+ unsigned int get_size () const
+ {
+ return min_size +
+ (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+ }
+
+ const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
+ {
+ return &lookupList;
+ }
+
+ template <typename TLookup>
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
+ if (unlikely (!(scriptList.sanitize (c, this) &&
+ featureList.sanitize (c, this) &&
+ reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
+ return_trace (false);
+
+#ifndef HB_NO_VAR
+ if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
+ return_trace (false);
+#endif
+
+ return_trace (true);
+ }
+
+ template <typename TLookup>
+ bool subset (hb_subset_layout_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->subset_context->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
+ reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
+ .serialize_subset (c->subset_context,
+ reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
+ this,
+ c);
+
+ reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
+ .serialize_subset (c->subset_context,
+ reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
+ this,
+ c);
+
+ out->scriptList.serialize_subset (c->subset_context,
+ scriptList,
+ this,
+ c);
+
+#ifndef HB_NO_VAR
+ if (version.to_int () >= 0x00010001u)
+ {
+ bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
+ if (!ret && version.major == 1)
+ {
+ out->version.major = 1;
+ out->version.minor = 0;
+ }
+ }
+#endif
+
+ return_trace (true);
+ }
};
struct GSUBGPOS
{
- bool has_data () const { return version.to_int (); }
+ unsigned int get_size () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.get_size ();
+#endif
+ default: return u.version.static_size;
+ }
+ }
+
+ template <typename TLookup>
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!u.version.sanitize (c))) return_trace (false);
+ switch (u.version.major) {
+ case 1: return_trace (u.version1.sanitize<TLookup> (c));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return_trace (u.version2.sanitize<TLookup> (c));
+#endif
+ default: return_trace (true);
+ }
+ }
+
+ template <typename TLookup>
+ bool subset (hb_subset_layout_context_t *c) const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.subset<TLookup> (c);
+#ifndef HB_NO_BEYOND_64K
+ case 2: return u.version2.subset<TLookup> (c);
+#endif
+ default: return false;
+ }
+ }
+
+ const ScriptList &get_script_list () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.scriptList;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.scriptList;
+#endif
+ default: return Null (ScriptList);
+ }
+ }
+ const FeatureList &get_feature_list () const
+ {
+ switch (u.version.major) {
+ case 1: return this+u.version1.featureList;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.featureList;
+#endif
+ default: return Null (FeatureList);
+ }
+ }
+ unsigned int get_lookup_count () const
+ {
+ switch (u.version.major) {
+ case 1: return (this+u.version1.lookupList).len;
+#ifndef HB_NO_BEYOND_64K
+ case 2: return (this+u.version2.lookupList).len;
+#endif
+ default: return 0;
+ }
+ }
+ const Lookup& get_lookup (unsigned int i) const
+ {
+ switch (u.version.major) {
+ case 1: return (this+u.version1.lookupList)[i];
+#ifndef HB_NO_BEYOND_64K
+ case 2: return (this+u.version2.lookupList)[i];
+#endif
+ default: return Null (Lookup);
+ }
+ }
+ const FeatureVariations &get_feature_variations () const
+ {
+ switch (u.version.major) {
+ case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
+#ifndef HB_NO_BEYOND_64K
+ case 2: return this+u.version2.featureVars;
+#endif
+ default: return Null (FeatureVariations);
+ }
+ }
+
+ bool has_data () const { return u.version.to_int (); }
unsigned int get_script_count () const
- { return (this+scriptList).len; }
+ { return get_script_list ().len; }
const Tag& get_script_tag (unsigned int i) const
- { return (this+scriptList).get_tag (i); }
+ { return get_script_list ().get_tag (i); }
unsigned int get_script_tags (unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */) const
- { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
+ { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
const Script& get_script (unsigned int i) const
- { return (this+scriptList)[i]; }
+ { return get_script_list ()[i]; }
bool find_script_index (hb_tag_t tag, unsigned int *index) const
- { return (this+scriptList).find_index (tag, index); }
+ { return get_script_list ().find_index (tag, index); }
unsigned int get_feature_count () const
- { return (this+featureList).len; }
+ { return get_feature_list ().len; }
hb_tag_t get_feature_tag (unsigned int i) const
- { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
+ { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
unsigned int get_feature_tags (unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */) const
- { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
+ { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
const Feature& get_feature (unsigned int i) const
- { return (this+featureList)[i]; }
+ { return get_feature_list ()[i]; }
bool find_feature_index (hb_tag_t tag, unsigned int *index) const
- { return (this+featureList).find_index (tag, index); }
-
- unsigned int get_lookup_count () const
- { return (this+lookupList).len; }
- const Lookup& get_lookup (unsigned int i) const
- { return (this+lookupList)[i]; }
+ { return get_feature_list ().find_index (tag, index); }
bool find_variations_index (const int *coords, unsigned int num_coords,
unsigned int *index) const
@@ -3587,18 +4303,17 @@ struct GSUBGPOS
*index = FeatureVariations::NOT_FOUND_INDEX;
return false;
#endif
- return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
- .find_index (coords, num_coords, index);
+ return get_feature_variations ().find_index (coords, num_coords, index);
}
const Feature& get_feature_variation (unsigned int feature_index,
unsigned int variations_index) const
{
#ifndef HB_NO_VAR
if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
- version.to_int () >= 0x00010001u)
+ u.version.to_int () >= 0x00010001u)
{
- const Feature *feature = (this+featureVars).find_substitute (variations_index,
- feature_index);
+ const Feature *feature = get_feature_variations ().find_substitute (variations_index,
+ feature_index);
if (feature)
return *feature;
}
@@ -3607,23 +4322,30 @@ struct GSUBGPOS
}
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
#ifndef HB_NO_VAR
- if (version.to_int () >= 0x00010001u)
- (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+ get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
#endif
}
+#ifndef HB_NO_VAR
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
+#endif
+
template <typename TLookup>
void closure_lookups (hb_face_t *face,
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */) const
{
hb_set_t visited_lookups, inactive_lookups;
- OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
+ hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
- for (unsigned lookup_index : + hb_iter (lookup_indexes))
+ c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
+
+ for (unsigned lookup_index : *lookup_indexes)
reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
hb_set_union (lookup_indexes, &visited_lookups);
@@ -3631,7 +4353,8 @@ struct GSUBGPOS
}
void prune_langsys (const hb_map_t *duplicate_feature_map,
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map,
+ const hb_set_t *layout_scripts,
+ 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);
@@ -3639,124 +4362,16 @@ struct GSUBGPOS
unsigned count = get_script_count ();
for (unsigned script_index = 0; script_index < count; script_index++)
{
+ const Tag& tag = get_script_tag (script_index);
+ if (!layout_scripts->has (tag)) continue;
const Script& s = get_script (script_index);
s.prune_langsys (&c, script_index);
}
}
- template <typename TLookup>
- bool subset (hb_subset_layout_context_t *c) const
- {
- TRACE_SUBSET (this);
- auto *out = c->subset_context->serializer->embed (*this);
- if (unlikely (!out)) return_trace (false);
-
- typedef LookupOffsetList<TLookup> TLookupList;
- reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
- .serialize_subset (c->subset_context,
- reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
- this,
- c);
-
- reinterpret_cast<Offset16To<RecordListOfFeature> &> (out->featureList)
- .serialize_subset (c->subset_context,
- reinterpret_cast<const Offset16To<RecordListOfFeature> &> (featureList),
- this,
- c);
-
- out->scriptList.serialize_subset (c->subset_context,
- scriptList,
- this,
- c);
-
-#ifndef HB_NO_VAR
- if (version.to_int () >= 0x00010001u)
- {
- bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
- if (!ret)
- {
- out->version.major = 1;
- out->version.minor = 0;
- }
- }
-#endif
-
- return_trace (true);
- }
-
- void find_duplicate_features (const hb_map_t *lookup_indices,
- const hb_set_t *feature_indices,
- hb_map_t *duplicate_feature_map /* OUT */) const
- {
- if (feature_indices->is_empty ()) return;
- hb_hashmap_t<hb_tag_t, hb_set_t *, (unsigned)-1, nullptr> unique_features;
- //find out duplicate features after subset
- for (unsigned i : feature_indices->iter ())
- {
- hb_tag_t t = get_feature_tag (i);
- if (t == unique_features.INVALID_KEY) 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);
- return;
- }
- if (unique_features.get (t))
- unique_features.get (t)->add (i);
- duplicate_feature_map->set (i, i);
- continue;
- }
-
- bool found = false;
-
- hb_set_t* same_tag_features = unique_features.get (t);
- for (unsigned other_f_index : same_tag_features->iter ())
- {
- const Feature& f = get_feature (i);
- const Feature& other_f = get_feature (other_f_index);
-
- auto f_iter =
- + hb_iter (f.lookupIndex)
- | hb_filter (lookup_indices)
- ;
-
- auto other_f_iter =
- + hb_iter (other_f.lookupIndex)
- | hb_filter (lookup_indices)
- ;
-
- bool is_equal = true;
- for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
- {
- unsigned a = *f_iter;
- unsigned b = *other_f_iter;
- if (a != b) { is_equal = false; break; }
- }
-
- if (is_equal == false || f_iter || other_f_iter) continue;
-
- found = true;
- duplicate_feature_map->set (i, other_f_index);
- break;
- }
-
- if (found == false)
- {
- same_tag_features->add (i);
- 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 */
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
hb_set_t *feature_indices /* IN/OUT */) const
{
#ifndef HB_NO_VAR
@@ -3764,8 +4379,7 @@ struct GSUBGPOS
// if the FeatureVariation's table and the alternate version(s) intersect the
// set of lookup indices.
hb_set_t alternate_feature_indices;
- if (version.to_int () >= 0x00010001u)
- (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
+ get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
if (unlikely (alternate_feature_indices.in_error()))
{
feature_indices->err ();
@@ -3773,9 +4387,8 @@ struct GSUBGPOS
}
#endif
- for (unsigned i : feature_indices->iter())
+ for (unsigned i : hb_iter (feature_indices))
{
- const Feature& f = get_feature (i);
hb_tag_t tag = get_feature_tag (i);
if (tag == HB_TAG ('p', 'r', 'e', 'f'))
// Note: Never ever drop feature 'pref', even if it's empty.
@@ -3784,8 +4397,17 @@ struct GSUBGPOS
// http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
continue;
- if (f.featureParams.is_null ()
- && !f.intersects_lookup_indexes (lookup_indices)
+
+ const Feature *f = &(get_feature (i));
+ const Feature** p = nullptr;
+ if (feature_substitutes_map->has (i, &p))
+ f = *p;
+
+ if (!f->featureParams.is_null () &&
+ tag == HB_TAG ('s', 'i', 'z', 'e'))
+ continue;
+
+ if (!f->intersects_lookup_indexes (lookup_indices)
#ifndef HB_NO_VAR
&& !alternate_feature_indices.has (i)
#endif
@@ -3794,36 +4416,10 @@ struct GSUBGPOS
}
}
- unsigned int get_size () const
- {
- return min_size +
- (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
- }
-
- template <typename TLookup>
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- typedef List16OfOffset16To<TLookup> TLookupList;
- if (unlikely (!(version.sanitize (c) &&
- likely (version.major == 1) &&
- scriptList.sanitize (c, this) &&
- featureList.sanitize (c, this) &&
- reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
- return_trace (false);
-
-#ifndef HB_NO_VAR
- if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
- return_trace (false);
-#endif
-
- return_trace (true);
- }
-
template <typename T>
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<T> (face);
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
@@ -3845,8 +4441,7 @@ struct GSUBGPOS
for (unsigned int i = 0; i < this->lookup_count; i++)
this->accels[i].init (table->get_lookup (i));
}
-
- void fini ()
+ ~accelerator_t ()
{
for (unsigned int i = 0; i < this->lookup_count; i++)
this->accels[i].fini ();
@@ -3860,21 +4455,15 @@ struct GSUBGPOS
};
protected:
- FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
- * to 0x00010000u */
- Offset16To<ScriptList>
- scriptList; /* ScriptList table */
- Offset16To<FeatureList>
- featureList; /* FeatureList table */
- Offset16To<LookupList>
- lookupList; /* LookupList table */
- Offset32To<FeatureVariations>
- featureVars; /* Offset to Feature Variations
- table--from beginning of table
- * (may be NULL). Introduced
- * in version 0x00010001. */
+ union {
+ FixedVersion<> version; /* Version identifier */
+ GSUBGPOSVersion1_2<SmallTypes> version1;
+#ifndef HB_NO_BEYOND_64K
+ GSUBGPOSVersion1_2<MediumTypes> version2;
+#endif
+ } u;
public:
- DEFINE_SIZE_MIN (10);
+ DEFINE_SIZE_MIN (4);
};
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index fbdedd0e2..e8091ec3e 100644
--- a/src/hb-ot-layout.cc
+++ b/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"
@@ -54,6 +54,9 @@
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
+
/**
* SECTION:hb-ot-layout
* @title: hb-ot-layout
@@ -76,7 +79,7 @@
* Tests whether a face includes any kerning data in the 'kern' table.
* Does NOT test for kerning lookups in the GPOS table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
bool
@@ -92,7 +95,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
* Tests whether a face includes any state-machine kerning in the 'kern' table.
* Does NOT examine the GPOS table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
bool
@@ -112,7 +115,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
*
* Does NOT examine the GPOS table.
*
- * Return value: %true is data found, %false otherwise
+ * Return value: `true` is data found, `false` otherwise
*
**/
bool
@@ -258,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;
}
}
@@ -270,7 +272,7 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
*
* Tests whether a face has any glyph classes defined in its GDEF table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
**/
hb_bool_t
@@ -361,6 +363,13 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
* Fetches a list of the caret positions defined for a ligature glyph in the GDEF
* table of the font. The list returned will begin at the offset provided.
*
+ * Note that a ligature that is formed from n characters will have n-1
+ * caret positions. The first character is not represented in the array,
+ * since its caret position is the glyph position.
+ *
+ * The positions returned by this function are 'unshaped', and will have to
+ * be fixed up for kerning that may be applied to the ligature glyph.
+ *
* Return value: Total number of ligature caret positions for @glyph.
*
**/
@@ -382,7 +391,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
*/
bool
-OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
hb_face_t *face) const
{
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -392,7 +401,7 @@ OT::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
@@ -452,7 +461,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
* Fetches the index if a given script tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the script is found, %false otherwise
+ * Return value: `true` if the script is found, `false` otherwise
*
**/
hb_bool_t
@@ -526,7 +535,7 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
* #HB_OT_LAYOUT_NO_SCRIPT_INDEX.
*
* Return value:
- * %true if one of the requested scripts is selected, %false if a fallback
+ * `true` if one of the requested scripts is selected, `false` if a fallback
* script is selected or if no scripts are selected.
*
* Since: 2.0.0
@@ -592,9 +601,13 @@ hb_ot_layout_table_select_script (hb_face_t *face,
* @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
*
* Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+ * Note that there might be duplicate feature tags, belonging to different
+ * script/language-system pairs of the table.
*
* Return value: Total number of feature tags.
*
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
@@ -619,7 +632,10 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
* Fetches the index for a given feature tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
+ *
**/
bool
hb_ot_layout_table_find_feature (hb_face_t *face,
@@ -659,6 +675,8 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
*
* Return value: Total number of language tags.
*
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_script_get_language_tags (hb_face_t *face,
@@ -686,7 +704,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
* Fetches the index of a given language tag in the specified face's GSUB table
* or GPOS table, underneath the specified script tag.
*
- * Return value: %true if the language tag is found, %false otherwise
+ * Return value: `true` if the language tag is found, `false` otherwise
*
* Since: 0.6.0
* Deprecated: 2.0.0
@@ -721,10 +739,10 @@ hb_ot_layout_script_find_language (hb_face_t *face,
* in the specified face's GSUB or GPOS table, underneath the specified script
* index.
*
- * If none of the given language tags is found, %false is returned and
+ * If none of the given language tags is found, `false` is returned and
* @language_index is set to the default language index.
*
- * Return value: %true if one of the given language tags is found, %false otherwise
+ * Return value: `true` if one of the given language tags is found, `false` otherwise
*
* Since: 2.0.0
**/
@@ -767,7 +785,9 @@ hb_ot_layout_script_select_language (hb_face_t *face,
* Fetches the index of a requested feature in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
*
**/
hb_bool_t
@@ -798,7 +818,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
* Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
*
* Since: 0.9.30
**/
@@ -837,6 +857,9 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
* returned will begin at the offset provided.
*
* Return value: Total number of features.
+ *
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
@@ -870,6 +893,9 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
* returned will begin at the offset provided.
*
* Return value: Total number of feature tags.
+ *
+ * Since: 0.6.0
+ *
**/
unsigned int
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
@@ -908,7 +934,9 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
* Fetches the index of a given feature tag in the specified face's GSUB table
* or GPOS table, underneath the specified script and language.
*
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
*
**/
hb_bool_t
@@ -999,7 +1027,7 @@ struct hb_collect_features_context_t
hb_collect_features_context_t (hb_face_t *face,
hb_tag_t table_tag,
hb_set_t *feature_indices_,
- const hb_tag_t *features)
+ const hb_tag_t *features)
: g (get_gsubgpos_table (face, table_tag)),
feature_indices (feature_indices_),
@@ -1026,7 +1054,7 @@ struct hb_collect_features_context_t
{
hb_tag_t tag = g.get_feature_tag (i);
if (features_set.has (tag))
- feature_indices_filter.add(i);
+ feature_indices_filter.add(i);
}
}
@@ -1158,9 +1186,12 @@ script_collect_features (hb_collect_features_context_t *c,
* hb_ot_layout_collect_features:
* @face: #hb_face_t to work upon
* @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect features for
- * @languages: The array of languages to collect features for
- * @features: The array of features to collect
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for,
+ * terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for,
+ * terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect,
+ * terminated by %HB_TAG_NONE
* @feature_indexes: (out): The array of feature indexes found for the query
*
* Fetches a list of all feature indexes in the specified face's GSUB table
@@ -1207,9 +1238,12 @@ hb_ot_layout_collect_features (hb_face_t *face,
* hb_ot_layout_collect_lookups:
* @face: #hb_face_t to work upon
* @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect lookups for
- * @languages: The array of languages to collect lookups for
- * @features: The array of features to collect lookups for
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for,
+ * terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for,
+ * terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for,
+ * terminated by %HB_TAG_NONE
* @lookup_indexes: (out): The array of lookup indexes found for the query
*
* Fetches a list of all feature-lookup indexes in the specified face's GSUB
@@ -1237,7 +1271,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
hb_set_next (&feature_indexes, &feature_index);)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
- g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
+ g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
}
@@ -1305,7 +1339,9 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
* Fetches a list of feature variations in the specified face's GSUB table
* or GPOS table, at the specified variation coordinates.
*
- * Return value: %true if feature variations were found, %false otherwise.
+ * Return value: `true` if feature variations were found, `false` otherwise.
+ *
+ * Since: 1.4.0
*
**/
hb_bool_t
@@ -1338,6 +1374,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
*
* Return value: Total number of lookups.
*
+ * Since: 1.4.0
+ *
**/
unsigned int
hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
@@ -1368,7 +1406,9 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
*
* Tests whether the specified face includes any GSUB substitutions.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 0.6.0
*
**/
hb_bool_t
@@ -1390,7 +1430,7 @@ hb_ot_layout_has_substitution (hb_face_t *face)
* Tests whether a specified lookup in the specified face would
* trigger a substitution on the given glyph sequence.
*
- * Return value: %true if a substitution would be triggered, %false otherwise
+ * Return value: `true` if a substitution would be triggered, `false` otherwise
*
* Since: 0.9.7
**/
@@ -1425,56 +1465,6 @@ hb_ot_layout_substitute_start (hb_font_t *font,
_hb_ot_layout_set_glyph_props (font, buffer);
}
-void
-hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
- bool (*filter) (const hb_glyph_info_t *info))
-{
- /* Merge clusters and delete filtered glyphs.
- * NOTE! We can't use out-buffer as we have positioning data. */
- unsigned int j = 0;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- hb_glyph_position_t *pos = buffer->pos;
- for (unsigned int i = 0; i < count; i++)
- {
- if (filter (&info[i]))
- {
- /* Merge clusters.
- * Same logic as buffer->delete_glyph(), but for in-place removal. */
-
- unsigned int cluster = info[i].cluster;
- if (i + 1 < count && cluster == info[i + 1].cluster)
- continue; /* Cluster survives; do nothing. */
-
- if (j)
- {
- /* Merge cluster backward. */
- if (cluster < info[j - 1].cluster)
- {
- unsigned int mask = info[i].mask;
- unsigned int old_cluster = info[j - 1].cluster;
- for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
- buffer->set_cluster (info[k - 1], cluster, mask);
- }
- continue;
- }
-
- if (i + 1 < count)
- buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
-
- continue;
- }
-
- if (j != i)
- {
- info[j] = info[i];
- pos[j] = pos[i];
- }
- j++;
- }
- buffer->len = j;
-}
-
/**
* hb_ot_layout_lookup_substitute_closure:
* @face: #hb_face_t to work upon
@@ -1491,17 +1481,13 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
unsigned int lookup_index,
hb_set_t *glyphs /* OUT */)
{
- hb_set_t cur_intersected_glyphs;
hb_map_t done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
- OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &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);
}
/**
@@ -1520,16 +1506,16 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
const hb_set_t *lookups,
hb_set_t *glyphs /* OUT */)
{
- hb_set_t cur_intersected_glyphs;
hb_map_t done_lookups_glyph_count;
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
- OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
- const OT::GSUB& gsub = *face->table.GSUB->table;
+ 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;
unsigned int iteration_count = 0;
unsigned int glyphs_length;
do
{
+ c.reset_lookup_visit_count ();
glyphs_length = glyphs->get_population ();
if (lookups)
{
@@ -1543,13 +1529,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
*/
@@ -1559,7 +1542,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
*
* Tests whether the specified face includes any GPOS positioning.
*
- * Return value: %true if the face has GPOS data, %false otherwise
+ * Return value: `true` if the face has GPOS data, `false` otherwise
*
**/
hb_bool_t
@@ -1580,7 +1563,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);
}
@@ -1595,7 +1578,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);
}
/**
@@ -1609,7 +1592,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);
}
@@ -1632,7 +1615,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
* For more information on this distinction, see the [`size` feature documentation](
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.10
**/
@@ -1644,7 +1627,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 ();
@@ -1676,6 +1659,8 @@ hb_ot_layout_get_size_params (hb_face_t *face,
return false;
}
+
+
/**
* hb_ot_layout_feature_get_name_ids:
* @face: #hb_face_t to work upon
@@ -1696,7 +1681,7 @@ hb_ot_layout_get_size_params (hb_face_t *face,
* Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
* "Character Variant" ('cvXX') features.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.0.0
**/
@@ -1795,28 +1780,28 @@ 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) :
table (*face->table.GSUB->table),
accels (face->table.GSUB->accels) {}
- const OT::GSUB &table;
+ const GSUB &table;
const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
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;
};
@@ -1825,16 +1810,18 @@ 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)
{
bool applied = false;
- if (accel.may_have (buffer->cur().codepoint) &&
+ if (accel.digest.may_have (buffer->cur().codepoint) &&
(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)
@@ -1842,6 +1829,10 @@ apply_forward (OT::hb_ot_apply_context_t *c,
else
(void) buffer->next_glyph ();
}
+
+ if (use_cache)
+ accel.cache_leave (c);
+
return ret;
}
@@ -1853,10 +1844,10 @@ apply_backward (OT::hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
do
{
- if (accel.may_have (buffer->cur().codepoint) &&
+ if (accel.digest.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--;
@@ -1867,37 +1858,40 @@ apply_backward (OT::hb_ot_apply_context_t *c,
}
template <typename Proxy>
-static inline void
+static inline bool
apply_string (OT::hb_ot_apply_context_t *c,
const typename Proxy::Lookup &lookup,
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
+ bool ret = false;
hb_buffer_t *buffer = c->buffer;
if (unlikely (!buffer->len || !c->lookup_mask))
- return;
+ return ret;
c->set_lookup_props (lookup.get_props ());
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);
+ ret = apply_forward (c, accel);
- if (!Proxy::inplace)
- buffer->swap_buffers ();
+ if (!Proxy::always_inplace)
+ buffer->sync ();
}
else
{
/* in-place backward substitution/positioning */
assert (!buffer->have_output);
buffer->idx = buffer->len - 1;
- apply_backward (c, accel);
+ ret = apply_backward (c, accel);
}
+
+ return ret;
}
template <typename Proxy>
@@ -1909,29 +1903,49 @@ 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++)
{
const stage_map_t *stage = &stages[table_index][stage_index];
for (; i < stage->last_lookup; i++)
{
- unsigned int lookup_index = lookups[table_index][i].index;
- if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
- c.set_lookup_index (lookup_index);
- c.set_lookup_mask (lookups[table_index][i].mask);
- c.set_auto_zwj (lookups[table_index][i].auto_zwj);
- c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
- c.set_random (lookups[table_index][i].random);
-
- apply_string<Proxy> (&c,
- proxy.table.get_lookup (lookup_index),
- proxy.accels[lookup_index]);
- (void) buffer->message (font, "end lookup %d", lookup_index);
+ auto &lookup = lookups[table_index][i];
+
+ unsigned int lookup_index = lookup.index;
+ if (!buffer->message (font, "start lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;
+
+ /* c.digest is a digest of all the current glyphs in the buffer
+ * (plus some past glyphs).
+ *
+ * Only try applying the lookup if there is any overlap. */
+ if (proxy.accels[lookup_index].digest.may_have (c.digest))
+ {
+ c.set_lookup_index (lookup_index);
+ c.set_lookup_mask (lookup.mask);
+ c.set_auto_zwj (lookup.auto_zwj);
+ c.set_auto_zwnj (lookup.auto_zwnj);
+ c.set_random (lookup.random);
+ c.set_per_syllable (lookup.per_syllable);
+
+ apply_string<Proxy> (&c,
+ proxy.table.get_lookup (lookup_index),
+ proxy.accels[lookup_index]);
+ }
+ else
+ (void) buffer->message (font, "skipped lookup %d feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));
+
+ (void) buffer->message (font, "end lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));
}
if (stage->pause_func)
- stage->pause_func (plan, font, buffer);
+ {
+ if (stage->pause_func (plan, font, buffer))
+ {
+ /* Refresh working buffer digest since buffer changed. */
+ c.digest = buffer->digest ();
+ }
+ }
}
}
@@ -1961,17 +1975,88 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
#ifndef HB_NO_BASE
/**
+ * hb_ot_layout_get_horizontal_baseline_tag_for_script:
+ * @script: a script tag.
+ *
+ * Fetches the dominant horizontal baseline tag used by @script.
+ *
+ * Return value: dominant baseline tag for the @script.
+ *
+ * Since: 4.0.0
+ **/
+hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)
+{
+ /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */
+ switch ((int) script)
+ {
+ /* Unicode-1.1 additions */
+ case HB_SCRIPT_BENGALI:
+ case HB_SCRIPT_DEVANAGARI:
+ case HB_SCRIPT_GUJARATI:
+ case HB_SCRIPT_GURMUKHI:
+ /* Unicode-2.0 additions */
+ case HB_SCRIPT_TIBETAN:
+ /* Unicode-4.0 additions */
+ case HB_SCRIPT_LIMBU:
+ /* Unicode-4.1 additions */
+ case HB_SCRIPT_SYLOTI_NAGRI:
+ /* Unicode-5.0 additions */
+ case HB_SCRIPT_PHAGS_PA:
+ /* Unicode-5.2 additions */
+ case HB_SCRIPT_MEETEI_MAYEK:
+ /* Unicode-6.1 additions */
+ case HB_SCRIPT_SHARADA:
+ case HB_SCRIPT_TAKRI:
+ /* Unicode-7.0 additions */
+ case HB_SCRIPT_MODI:
+ case HB_SCRIPT_SIDDHAM:
+ case HB_SCRIPT_TIRHUTA:
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_MARCHEN:
+ case HB_SCRIPT_NEWA:
+ /* Unicode-10.0 additions */
+ case HB_SCRIPT_SOYOMBO:
+ case HB_SCRIPT_ZANABAZAR_SQUARE:
+ /* Unicode-11.0 additions */
+ case HB_SCRIPT_DOGRA:
+ case HB_SCRIPT_GUNJALA_GONDI:
+ /* Unicode-12.0 additions */
+ case HB_SCRIPT_NANDINAGARI:
+ return HB_OT_LAYOUT_BASELINE_TAG_HANGING;
+
+ /* Unicode-1.1 additions */
+ case HB_SCRIPT_HANGUL:
+ case HB_SCRIPT_HAN:
+ case HB_SCRIPT_HIRAGANA:
+ case HB_SCRIPT_KATAKANA:
+ /* Unicode-3.0 additions */
+ case HB_SCRIPT_BOPOMOFO:
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_TANGUT:
+ /* Unicode-10.0 additions */
+ case HB_SCRIPT_NUSHU:
+ /* Unicode-13.0 additions */
+ case HB_SCRIPT_KHITAN_SMALL_SCRIPT:
+ return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT;
+
+ default:
+ return HB_OT_LAYOUT_BASELINE_TAG_ROMAN;
+ }
+}
+
+/**
* hb_ot_layout_get_baseline:
* @font: a font
* @baseline_tag: a baseline tag
* @direction: text direction.
* @script_tag: script tag.
* @language_tag: language tag, currently unused.
- * @coord: (out): baseline value if found.
+ * @coord: (out) (nullable): baseline value if found.
*
* Fetches a baseline value from the face.
*
- * Return value: %true if found baseline value in the font.
+ * Return value: `true` if found baseline value in the font.
*
* Since: 2.6.0
**/
@@ -1983,13 +2068,231 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */)
{
- bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
+ return font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
+}
+
+/**
+ * hb_ot_layout_get_baseline_with_fallback:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script_tag: script tag.
+ * @language_tag: language tag, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_position_t *coord /* OUT */)
+{
+ if (hb_ot_layout_get_baseline (font,
+ baseline_tag,
+ direction,
+ script_tag,
+ language_tag,
+ coord))
+ return;
+
+ /* Synthesize missing baselines.
+ * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts
+ */
+ switch (baseline_tag)
+ {
+ case HB_OT_LAYOUT_BASELINE_TAG_ROMAN:
+ *coord = 0; // FIXME origin ?
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_MATH:
+ {
+ hb_codepoint_t glyph;
+ hb_glyph_extents_t extents;
+ if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
+ (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
+ hb_font_get_nominal_glyph (font, '-', &glyph)) &&
+ hb_font_get_glyph_extents (font, glyph, &extents))
+ {
+ *coord = extents.y_bearing + extents.height / 2;
+ }
+ else
+ {
+ hb_position_t x_height = font->y_scale / 2;
+#ifndef HB_NO_METRICS
+ hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
+#endif
+ *coord = x_height / 2;
+ }
+ }
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT:
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT:
+ {
+ hb_position_t embox_top, embox_bottom;
+
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+ direction,
+ script_tag,
+ language_tag,
+ &embox_top);
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+ direction,
+ script_tag,
+ language_tag,
+ &embox_bottom);
+
+ if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
+ *coord = embox_top + (embox_bottom - embox_top) / 10;
+ else
+ *coord = embox_bottom + (embox_top - embox_bottom) / 10;
+ }
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
+ if (hb_ot_layout_get_baseline (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+ direction,
+ script_tag,
+ language_tag,
+ coord))
+ *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+ else
+ {
+ hb_font_extents_t font_extents;
+ hb_font_get_extents_for_direction (font, direction, &font_extents);
+ *coord = font_extents.ascender;
+ }
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
+ if (hb_ot_layout_get_baseline (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+ direction,
+ script_tag,
+ language_tag,
+ coord))
+ *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+ else
+ {
+ hb_font_extents_t font_extents;
+ hb_font_get_extents_for_direction (font, direction, &font_extents);
+ *coord = font_extents.descender;
+ }
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_HANGING:
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ {
+ hb_codepoint_t ch;
+ hb_codepoint_t glyph;
+ hb_glyph_extents_t extents;
+
+ /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */
+ switch ((int) script_tag)
+ {
+ /* Unicode-1.1 additions */
+ case HB_SCRIPT_BENGALI: ch = 0x0995u; break;
+ case HB_SCRIPT_DEVANAGARI: ch = 0x0915u; break;
+ case HB_SCRIPT_GUJARATI: ch = 0x0a95u; break;
+ case HB_SCRIPT_GURMUKHI: ch = 0x0a15u; break;
+ /* Unicode-2.0 additions */
+ case HB_SCRIPT_TIBETAN: ch = 0x0f40u; break;
+ /* Unicode-4.0 additions */
+ case HB_SCRIPT_LIMBU: ch = 0x1901u; break;
+ /* Unicode-4.1 additions */
+ case HB_SCRIPT_SYLOTI_NAGRI: ch = 0xa807u; break;
+ /* Unicode-5.0 additions */
+ case HB_SCRIPT_PHAGS_PA: ch = 0xa840u; break;
+ /* Unicode-5.2 additions */
+ case HB_SCRIPT_MEETEI_MAYEK: ch = 0xabc0u; break;
+ /* Unicode-6.1 additions */
+ case HB_SCRIPT_SHARADA: ch = 0x11191u; break;
+ case HB_SCRIPT_TAKRI: ch = 0x1168cu; break;
+ /* Unicode-7.0 additions */
+ case HB_SCRIPT_MODI: ch = 0x1160eu;break;
+ case HB_SCRIPT_SIDDHAM: ch = 0x11590u; break;
+ case HB_SCRIPT_TIRHUTA: ch = 0x1148fu; break;
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_MARCHEN: ch = 0x11c72u; break;
+ case HB_SCRIPT_NEWA: ch = 0x1140eu; break;
+ /* Unicode-10.0 additions */
+ case HB_SCRIPT_SOYOMBO: ch = 0x11a5cu; break;
+ case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break;
+ /* Unicode-11.0 additions */
+ case HB_SCRIPT_DOGRA: ch = 0x1180au; break;
+ case HB_SCRIPT_GUNJALA_GONDI: ch = 0x11d6cu; break;
+ /* Unicode-12.0 additions */
+ case HB_SCRIPT_NANDINAGARI: ch = 0x119b0u; break;
+ default: ch = 0; break;
+ }
+
+ if (ch &&
+ hb_font_get_nominal_glyph (font, ch, &glyph) &&
+ hb_font_get_glyph_extents (font, glyph, &extents))
+ *coord = extents.y_bearing;
+ else
+ *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
+ }
+ else
+ *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL:
+ {
+ hb_position_t top, bottom;
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+ direction,
+ script_tag,
+ language_tag,
+ &top);
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+ direction,
+ script_tag,
+ language_tag,
+ &bottom);
+ *coord = (top + bottom) / 2;
- if (result && coord)
- *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord);
+ }
+ break;
+
+ case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL:
+ {
+ hb_position_t top, bottom;
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
+ direction,
+ script_tag,
+ language_tag,
+ &top);
+ hb_ot_layout_get_baseline_with_fallback (font,
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
+ direction,
+ script_tag,
+ language_tag,
+ &bottom);
+ *coord = (top + bottom) / 2;
+
+ }
+ break;
- return result;
+ case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE:
+ default:
+ *coord = 0;
+ break;
+ }
}
+
#endif
@@ -1999,11 +2302,6 @@ struct hb_get_glyph_alternates_dispatch_t :
static return_t default_return_value () { return 0; }
bool stop_sublookup_iteration (return_t r) const { return r; }
- hb_face_t *face;
-
- hb_get_glyph_alternates_dispatch_t (hb_face_t *face) :
- face (face) {}
-
private:
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
@@ -2017,6 +2315,7 @@ struct hb_get_glyph_alternates_dispatch_t :
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
};
+#ifndef HB_NO_LAYOUT_RARELY_USED
/**
* hb_ot_layout_lookup_get_glyph_alternates:
* @face: a face.
@@ -2042,11 +2341,79 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */)
{
- hb_get_glyph_alternates_dispatch_t c (face);
+ hb_get_glyph_alternates_dispatch_t c;
const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);
if (!ret && alternate_count) *alternate_count = 0;
return ret;
}
+
+struct hb_position_single_dispatch_t :
+ hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
+{
+ static return_t default_return_value () { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+
+ private:
+ template <typename T, typename ...Ts> auto
+ _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+ ( obj.position_single (std::forward<Ts> (ds)...) )
+ template <typename T, typename ...Ts> auto
+ _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+ ( default_return_value () )
+ public:
+ template <typename T, typename ...Ts> auto
+ dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+ ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+};
+
+/**
+ * hb_ot_layout_lookup_get_optical_bound:
+ * @font: a font.
+ * @lookup_index: index of the feature lookup to query.
+ * @direction: edge of the glyph to query.
+ * @glyph: a glyph id.
+ *
+ * Fetches the optical bound of a glyph positioned at the margin of text.
+ * The direction identifies which edge of the glyph to query.
+ *
+ * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
+ *
+ * Since: 5.3.0
+ **/
+hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
+ unsigned lookup_index,
+ hb_direction_t direction,
+ hb_codepoint_t glyph)
+{
+ const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+ hb_glyph_position_t pos = {0};
+ hb_position_single_dispatch_t c;
+ lookup.dispatch (&c, font, direction, glyph, pos);
+ hb_position_t ret = 0;
+ switch (direction)
+ {
+ case HB_DIRECTION_LTR:
+ ret = pos.x_offset;
+ break;
+ case HB_DIRECTION_RTL:
+ ret = pos.x_advance - pos.x_offset;
+ break;
+ case HB_DIRECTION_TTB:
+ ret = pos.y_offset;
+ break;
+ case HB_DIRECTION_BTT:
+ ret = pos.y_advance - pos.y_offset;
+ break;
+ case HB_DIRECTION_INVALID:
+ default:
+ break;
+ }
+ return ret;
+}
+#endif
+
+
#endif
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index d47ba0fc9..f7b488f87 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -332,31 +332,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output /* OUT. May be NULL */);
-#ifdef HB_NOT_IMPLEMENTED
-typedef struct
-{
- const hb_codepoint_t *before,
- unsigned int before_length,
- const hb_codepoint_t *input,
- unsigned int input_length,
- const hb_codepoint_t *after,
- unsigned int after_length,
-} hb_ot_layout_glyph_sequence_t;
-
-typedef hb_bool_t
-(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
- hb_tag_t table_tag,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- void *user_data);
-
-HB_EXTERN void
-Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int lookup_index,
- hb_ot_layout_glyph_sequence_func_t callback,
- void *user_data);
-#endif
/* Variations support */
@@ -411,19 +386,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
hb_set_t *glyphs);
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_substitute (hb_font_t *font,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- unsigned int out_size,
- hb_codepoint_t *glyphs_out, /* OUT */
- unsigned int *clusters_out, /* OUT */
- unsigned int *out_length /* OUT */);
-#endif
-
-
/*
* GPOS
*/
@@ -431,15 +393,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t *font,
HB_EXTERN hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_position (hb_font_t *font,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- hb_glyph_position_t *positions /* IN / OUT */);
-#endif
-
/* Optical 'size' feature info. Returns true if found.
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
HB_EXTERN hb_bool_t
@@ -450,6 +403,16 @@ 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 */);
+HB_EXTERN hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
+ unsigned lookup_index,
+ hb_direction_t direction,
+ hb_codepoint_t glyph);
+
+
+/*
+ * GSUB/GPOS
+ */
HB_EXTERN hb_bool_t
hb_ot_layout_feature_get_name_ids (hb_face_t *face,
@@ -470,6 +433,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
unsigned int *char_count /* IN/OUT. May be NULL */,
hb_codepoint_t *characters /* OUT. May be NULL */);
+
/*
* BASE
*/
@@ -487,9 +451,11 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
* if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
* In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
@@ -503,14 +469,19 @@ typedef enum {
HB_OT_LAYOUT_BASELINE_TAG_HANGING = HB_TAG ('h','a','n','g'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT = HB_TAG ('i','c','f','b'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT = HB_TAG ('i','c','f','t'),
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL = HB_TAG ('I','c','f','c'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT = HB_TAG ('i','d','e','o'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'),
+ HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL = HB_TAG ('I','d','c','e'),
HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'),
/*< private >*/
_HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_layout_baseline_tag_t;
+HB_EXTERN hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script);
+
HB_EXTERN hb_bool_t
hb_ot_layout_get_baseline (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
@@ -519,6 +490,14 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_position_t *coord /* OUT */);
+
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh
index b15d05383..9505d5f14 100644
--- a/src/hb-ot-layout.hh
+++ b/src/hb-ot-layout.hh
@@ -102,19 +102,19 @@ HB_INTERNAL void
hb_ot_layout_substitute_start (hb_font_t *font,
hb_buffer_t *buffer);
-HB_INTERNAL void
-hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
- bool (*filter) (const hb_glyph_info_t *info));
-
namespace OT {
struct hb_ot_apply_context_t;
- struct SubstLookup;
struct hb_ot_layout_lookup_accelerator_t;
+namespace Layout {
+namespace GSUB_impl {
+ struct SubstLookup;
+}
+}
}
HB_INTERNAL void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
- const OT::SubstLookup &lookup,
+ const OT::Layout::GSUB_impl::SubstLookup &lookup,
const OT::hb_ot_layout_lookup_accelerator_t &accel);
@@ -168,17 +168,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
return start;
}
-static inline void
-_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font HB_UNUSED,
- hb_buffer_t *buffer)
-{
- hb_glyph_info_t *info = buffer->info;
- unsigned int count = buffer->len;
- for (unsigned int i = 0; i < count; i++)
- info[i].syllable() = 0;
-}
-
/* unicode_props */
@@ -350,24 +339,20 @@ _hb_glyph_info_is_continuation (const hb_glyph_info_t *info)
{
return info->unicode_props() & UPROPS_MASK_CONTINUATION;
}
-/* Loop over grapheme. Based on foreach_cluster(). */
-#define foreach_grapheme(buffer, start, end) \
- for (unsigned int \
- _count = buffer->len, \
- start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \
- start < _count; \
- start = end, end = _hb_next_grapheme (buffer, start))
-static inline unsigned int
-_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start)
-{
- hb_glyph_info_t *info = buffer->info;
- unsigned int count = buffer->len;
+static inline bool
+_hb_grapheme_group_func (const hb_glyph_info_t& a HB_UNUSED,
+ const hb_glyph_info_t& b)
+{ return _hb_glyph_info_is_continuation (&b); }
- while (++start < count && _hb_glyph_info_is_continuation (&info[start]))
- ;
+#define foreach_grapheme(buffer, start, end) \
+ foreach_group (buffer, start, end, _hb_grapheme_group_func)
- return start;
+static inline void
+_hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer)
+{
+ buffer->reverse_groups (_hb_grapheme_group_func,
+ buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
}
static inline bool
@@ -486,7 +471,8 @@ _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
}
static inline uint8_t
-_hb_allocate_lig_id (hb_buffer_t *buffer) {
+_hb_allocate_lig_id (hb_buffer_t *buffer)
+{
uint8_t lig_id = buffer->next_serial () & 0x07;
if (unlikely (!lig_id))
lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
@@ -562,7 +548,7 @@ _hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
-static inline void
+static inline bool
_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -571,6 +557,7 @@ _hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_clear_substituted (&info[i]);
+ return false;
}
@@ -599,13 +586,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);
}
@@ -615,7 +600,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/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 12ceea578..8882dbacc 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -43,16 +43,16 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_o
hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
- const hb_segment_properties_t *props_)
+ const hb_segment_properties_t &props_)
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
feature_infos.init ();
for (unsigned int table_index = 0; table_index < 2; table_index++)
stages[table_index].init ();
face = face_;
- props = *props_;
+ props = props_;
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
* features not available in either table and not waste precious bits for them. */
@@ -109,6 +109,21 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag,
info->stage[1] = current_stage[1];
}
+bool hb_ot_map_builder_t::has_feature (hb_tag_t tag)
+{
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
+ if (hb_ot_layout_language_find_feature (face,
+ table_tags[table_index],
+ script_index[table_index],
+ language_index[table_index],
+ tag,
+ nullptr))
+ return true;
+ }
+ return false;
+}
+
void
hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
unsigned int table_index,
@@ -117,7 +132,9 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
hb_mask_t mask,
bool auto_zwnj,
bool auto_zwj,
- bool random)
+ bool random,
+ bool per_syllable,
+ hb_tag_t feature_tag)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
@@ -145,6 +162,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
lookup->random = random;
+ lookup->per_syllable = per_syllable;
+ lookup->feature_tag = feature_tag;
}
offset += len;
@@ -195,24 +214,26 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
if (feature_infos.length)
{
feature_infos.qsort ();
+ auto *f = feature_infos.arrayZ;
unsigned int j = 0;
- for (unsigned int i = 1; i < feature_infos.length; i++)
- if (feature_infos[i].tag != feature_infos[j].tag)
- feature_infos[++j] = feature_infos[i];
+ unsigned count = feature_infos.length;
+ for (unsigned int i = 1; i < count; i++)
+ if (f[i].tag != f[j].tag)
+ f[++j] = f[i];
else {
- if (feature_infos[i].flags & F_GLOBAL) {
- feature_infos[j].flags |= F_GLOBAL;
- feature_infos[j].max_value = feature_infos[i].max_value;
- feature_infos[j].default_value = feature_infos[i].default_value;
+ if (f[i].flags & F_GLOBAL) {
+ f[j].flags |= F_GLOBAL;
+ f[j].max_value = f[i].max_value;
+ f[j].default_value = f[i].default_value;
} else {
- if (feature_infos[j].flags & F_GLOBAL)
- feature_infos[j].flags ^= F_GLOBAL;
- feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value);
+ if (f[j].flags & F_GLOBAL)
+ f[j].flags ^= F_GLOBAL;
+ f[j].max_value = hb_max (f[j].max_value, f[i].max_value);
/* Inherit default_value from j */
}
- feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
- feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]);
- feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+ f[j].flags |= (f[i].flags & F_HAS_FALLBACK);
+ f[j].stage[0] = hb_min (f[j].stage[0], f[i].stage[0]);
+ f[j].stage[1] = hb_min (f[j].stage[1], f[i].stage[1]);
}
feature_infos.shrink (j + 1);
}
@@ -222,7 +243,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int next_bit = hb_popcount (HB_GLYPH_FLAG_DEFINED) + 1;
- for (unsigned int i = 0; i < feature_infos.length; i++)
+ unsigned count = feature_infos.length;
+ for (unsigned int i = 0; i < count; i++)
{
const feature_info_t *info = &feature_infos[i];
@@ -277,6 +299,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
map->random = !!(info->flags & F_RANDOM);
+ map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = global_bit_shift;
@@ -290,7 +313,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
- feature_infos.shrink (0); /* Done with these */
+ //feature_infos.shrink (0); /* Done with these */
add_gsub_pause (nullptr);
@@ -299,6 +322,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
/* Collect lookup indices for features */
+ auto &lookups = m.lookups[table_index];
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
@@ -311,35 +335,39 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
key.variations_index[table_index],
global_bit_mask);
- for (unsigned i = 0; i < m.features.length; i++)
- if (m.features[i].stage[table_index] == stage)
+ for (auto &feature : m.features)
+ {
+ if (feature.stage[table_index] == stage)
add_lookups (m, table_index,
- m.features[i].index[table_index],
+ feature.index[table_index],
key.variations_index[table_index],
- m.features[i].mask,
- m.features[i].auto_zwnj,
- m.features[i].auto_zwj,
- m.features[i].random);
+ feature.mask,
+ feature.auto_zwnj,
+ feature.auto_zwj,
+ feature.random,
+ feature.per_syllable,
+ feature.tag);
+ }
/* Sort lookups and merge duplicates */
- if (last_num_lookups < m.lookups[table_index].length)
+ if (last_num_lookups < lookups.length)
{
- m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].length);
+ lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort ();
unsigned int j = last_num_lookups;
- for (unsigned int i = j + 1; i < m.lookups[table_index].length; i++)
- if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
- m.lookups[table_index][++j] = m.lookups[table_index][i];
+ for (unsigned int i = j + 1; i < lookups.length; i++)
+ if (lookups.arrayZ[i].index != lookups.arrayZ[j].index)
+ lookups.arrayZ[++j] = lookups.arrayZ[i];
else
{
- m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
- m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
- m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+ lookups.arrayZ[j].mask |= lookups.arrayZ[i].mask;
+ lookups.arrayZ[j].auto_zwnj &= lookups.arrayZ[i].auto_zwnj;
+ lookups.arrayZ[j].auto_zwj &= lookups.arrayZ[i].auto_zwj;
}
- m.lookups[table_index].shrink (j + 1);
+ lookups.shrink (j + 1);
}
- last_num_lookups = m.lookups[table_index].length;
+ last_num_lookups = lookups.length;
if (stage_index < stages[table_index].length && stages[table_index][stage_index].index == stage) {
hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 5f2afae28..efc8cae96 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -56,6 +56,7 @@ struct hb_ot_map_t
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
unsigned int random : 1;
+ unsigned int per_syllable : 1;
int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
@@ -66,7 +67,9 @@ struct hb_ot_map_t
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
unsigned short random : 1;
+ unsigned short per_syllable : 1;
hb_mask_t mask;
+ hb_tag_t feature_tag;
HB_INTERNAL static int cmp (const void *pa, const void *pb)
{
@@ -76,7 +79,9 @@ struct hb_ot_map_t
}
};
- typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
+ /* Pause functions return true if new glyph indices might have been
+ * added to the buffer. This is used to update buffer digest. */
+ typedef bool (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
struct stage_map_t {
unsigned int last_lookup; /* Cumulative */
@@ -85,13 +90,13 @@ struct hb_ot_map_t
void init ()
{
- memset (this, 0, sizeof (*this));
+ hb_memset (this, 0, sizeof (*this));
- features.init ();
+ features.init0 ();
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
- lookups[table_index].init ();
- stages[table_index].init ();
+ lookups[table_index].init0 ();
+ stages[table_index].init0 ();
}
}
void fini ()
@@ -137,19 +142,15 @@ struct hb_ot_map_t
return map ? map->stage[table_index] : UINT_MAX;
}
- void get_stage_lookups (unsigned int table_index, unsigned int stage,
- const struct lookup_map_t **plookups, unsigned int *lookup_count) const
+ hb_array_t<const hb_ot_map_t::lookup_map_t>
+ get_stage_lookups (unsigned int table_index, unsigned int stage) const
{
if (unlikely (stage > stages[table_index].length))
- {
- *plookups = nullptr;
- *lookup_count = 0;
- return;
- }
+ return hb_array<const hb_ot_map_t::lookup_map_t> (nullptr, 0);
+
unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
unsigned int end = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
- *plookups = end == start ? nullptr : &lookups[table_index][start];
- *lookup_count = end - start;
+ return lookups[table_index].as_array ().sub_array (start, end - start);
}
HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
@@ -165,7 +166,7 @@ struct hb_ot_map_t
private:
- hb_mask_t global_mask;
+ hb_mask_t global_mask = 0;
hb_sorted_vector_t<feature_map_t> features;
hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
@@ -183,7 +184,8 @@ enum hb_ot_map_feature_flags_t
F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
- F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
+ F_RANDOM = 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
+ F_PER_SYLLABLE = 0x0040u /* Contain lookup application to within syllable. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
@@ -201,7 +203,7 @@ struct hb_ot_map_builder_t
public:
HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
- const hb_segment_properties_t *props_);
+ const hb_segment_properties_t &props_);
HB_INTERNAL ~hb_ot_map_builder_t ();
@@ -209,6 +211,8 @@ struct hb_ot_map_builder_t
hb_ot_map_feature_flags_t flags=F_NONE,
unsigned int value=1);
+ HB_INTERNAL bool has_feature (hb_tag_t tag);
+
void add_feature (const hb_ot_map_feature_t &feat)
{ add_feature (feat.tag, feat.flags); }
@@ -237,7 +241,9 @@ struct hb_ot_map_builder_t
hb_mask_t mask,
bool auto_zwnj = true,
bool auto_zwj = true,
- bool random = false);
+ bool random = false,
+ bool per_syllable = false,
+ hb_tag_t feature_tag = HB_TAG(' ',' ',' ',' '));
struct feature_info_t {
hb_tag_t tag;
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index c2e365dbd..93953370e 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -77,11 +77,11 @@ struct MathConstants
HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
if (unlikely (!p)) return_trace (nullptr);
- memcpy (p, percentScaleDown, HBINT16::static_size * 2);
+ hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
if (unlikely (!m)) return_trace (nullptr);
- memcpy (m, minHeight, HBUINT16::static_size * 2);
+ hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
unsigned count = ARRAY_LENGTH (mathValueRecords);
for (unsigned i = 0; i < count; i++)
@@ -369,6 +369,37 @@ struct MathKern
return kernValue[i].get_x_value (font, this);
}
+ unsigned int get_entries (unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+ hb_font_t *font) const
+ {
+ const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
+ const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
+ const unsigned int entriesCount = heightCount + 1;
+
+ if (entries_count)
+ {
+ unsigned int start = hb_min (start_offset, entriesCount);
+ unsigned int end = hb_min (start + *entries_count, entriesCount);
+ *entries_count = end - start;
+
+ for (unsigned int i = 0; i < *entries_count; i++) {
+ unsigned int j = start + i;
+
+ hb_position_t max_height;
+ if (j == heightCount) {
+ max_height = INT32_MAX;
+ } else {
+ max_height = correctionHeight[j].get_y_value (font, this);
+ }
+
+ kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
+ }
+ }
+ return entriesCount;
+ }
+
protected:
HBUINT16 heightCount;
UnsizedArrayOf<MathValueRecord>
@@ -423,6 +454,24 @@ struct MathKernInfoRecord
return (base+mathKern[idx]).get_value (correction_height, font);
}
+ unsigned int get_kernings (hb_ot_math_kern_t kern,
+ unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+ hb_font_t *font,
+ const void *base) const
+ {
+ unsigned int idx = kern;
+ if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
+ if (entries_count) *entries_count = 0;
+ return 0;
+ }
+ return (base+mathKern[idx]).get_entries (start_offset,
+ entries_count,
+ kern_entries,
+ font);
+ }
+
protected:
/* Offset to MathKern table for each corner -
* from the beginning of MathKernInfo table. May be NULL. */
@@ -473,6 +522,22 @@ struct MathKernInfo
return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
}
+ unsigned int get_kernings (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+ return mathKernInfoRecords[index].get_kernings (kern,
+ start_offset,
+ entries_count,
+ kern_entries,
+ font,
+ this);
+ }
+
protected:
Offset16To<Coverage>
mathKernCoverage;
@@ -511,7 +576,8 @@ struct MathGlyphInfo
| hb_map_retains_sorting (glyph_map)
;
- out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
+ if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
+ else out->extendedShapeCoverage = 0;
out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
return_trace (true);
@@ -544,6 +610,19 @@ struct MathGlyphInfo
hb_font_t *font) const
{ return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
+ hb_position_t get_kernings (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+ hb_font_t *font) const
+ { return (this+mathKernInfo).get_kernings (glyph,
+ kern,
+ start_offset,
+ entries_count,
+ kern_entries,
+ font); }
+
protected:
/* Offset to MathItalicsCorrectionInfo table -
* from the beginning of MathGlyphInfo table. */
@@ -707,7 +786,7 @@ struct MathGlyphAssembly
if (parts_count)
{
int64_t mult = font->dir_mult (direction);
- for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
+ for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
hb_array (parts, *parts_count)))
_.first.extract (_.second, mult, font);
}
@@ -776,7 +855,7 @@ struct MathGlyphConstruction
if (variants_count)
{
int64_t mult = font->dir_mult (direction);
- for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
+ for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
hb_array (variants, *variants_count)))
_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
}
@@ -884,8 +963,11 @@ struct MathVariants
if (!o) return_trace (false);
o->serialize_subset (c, glyphConstruction[i], this);
}
-
- out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
+
+ if (new_vert_coverage)
+ out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
+
+ if (new_hori_coverage)
out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
return_trace (true);
}
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 5781d25f2..c515867bd 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face has a `MATH` table.
*
- * Return value: %true if the table is found, %false otherwise
+ * Return value: `true` if the table is found, `false` otherwise
*
* Since: 1.3.3
**/
@@ -142,7 +142,7 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
*
* Tests whether the given glyph index is an extended shape in the face.
*
- * Return value: %true if the glyph is an extended shape, %false otherwise
+ * Return value: `true` if the glyph is an extended shape, `false` otherwise
*
* Since: 1.3.3
**/
@@ -185,6 +185,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
}
/**
+ * hb_ot_math_get_glyph_kernings:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the kernings
+ * @kern: The #hb_ot_math_kern_t from which to retrieve the kernings
+ * @start_offset: offset of the first kern entry to retrieve
+ * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return;
+ * Output = the actual number of kern entries returned
+ * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned
+ *
+ * Fetches the raw MathKern (cut-in) data for the specified font, glyph index,
+ * and @kern. The corresponding list of kern values and correction heights is
+ * returned as a list of #hb_ot_math_kern_entry_t structs.
+ *
+ * See also #hb_ot_math_get_glyph_kerning, which handles selecting the
+ * appropriate kern value for a given correction height.
+ *
+ * <note>For a glyph with @n defined kern values (where @n > 0), there are only
+ * @n−1 defined correction heights, as each correction height defines a boundary
+ * past which the next kern value should be selected. Therefore, only the
+ * #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t
+ * actually comes from the font; its corresponding
+ * #hb_ot_math_kern_entry_t.max_correction_height is always set to
+ * <code>INT32_MAX</code>.</note>
+ *
+ * Return value: the total number of kern values available or zero
+ *
+ * Since: 3.4.0
+ **/
+unsigned int
+hb_ot_math_get_glyph_kernings (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries /* OUT */)
+{
+ return font->face->table.MATH->get_glyph_info().get_kernings (glyph,
+ kern,
+ start_offset,
+ entries_count,
+ kern_entries,
+ font);
+}
+
+/**
* hb_ot_math_get_glyph_variants:
* @font: #hb_font_t to work upon
* @glyph: The index of the glyph to stretch
diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h
index d3ffa19d8..1378a0639 100644
--- a/src/hb-ot-math.h
+++ b/src/hb-ot-math.h
@@ -50,14 +50,18 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
/**
- * HB_OT_MATH_SCRIPT:
+ * HB_OT_TAG_MATH_SCRIPT:
*
- * OpenType script tag for math shaping, for use with
- * Use with hb_buffer_set_script().
+ * OpenType script tag, `math`, for features specific to math shaping.
*
- * Since: 1.3.3
+ * <note>#HB_OT_TAG_MATH_SCRIPT is not a valid #hb_script_t and should only be
+ * used with functions that accept raw OpenType script tags, such as
+ * #hb_ot_layout_collect_features. In other cases, #HB_SCRIPT_MATH should be
+ * used instead.</note>
+ *
+ * Since: 3.4.0
*/
-#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
+#define HB_OT_TAG_MATH_SCRIPT HB_TAG('m','a','t','h')
/* Types */
@@ -205,6 +209,20 @@ typedef enum {
} hb_ot_math_kern_t;
/**
+ * hb_ot_math_kern_entry_t:
+ * @max_correction_height: The maximum height at which this entry should be used
+ * @kern_value: The kern value of the entry
+ *
+ * Data type to hold math kerning (cut-in) information for a glyph.
+ *
+ * Since: 3.4.0
+ */
+typedef struct {
+ hb_position_t max_correction_height;
+ hb_position_t kern_value;
+} hb_ot_math_kern_entry_t;
+
+/**
* hb_ot_math_glyph_variant_t:
* @glyph: The glyph index of the variant
* @advance: The advance width of the variant
@@ -281,6 +299,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
hb_position_t correction_height);
HB_EXTERN unsigned int
+hb_ot_math_get_glyph_kernings (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ unsigned int start_offset,
+ unsigned int *entries_count, /* IN/OUT */
+ hb_ot_math_kern_entry_t *kern_entries /* OUT */);
+
+HB_EXTERN unsigned int
hb_ot_math_get_glyph_variants (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh
index e31447f8f..e1b68bcf9 100644
--- a/src/hb-ot-meta-table.hh
+++ b/src/hb-ot-meta-table.hh
@@ -71,9 +71,9 @@ struct meta
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{ table = hb_sanitize_context_t ().reference_table<meta> (face); }
- void fini () { table.destroy (); }
+ ~accelerator_t () { table.destroy (); }
hb_blob_t *reference_entry (hb_tag_t tag) const
{ return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); }
@@ -84,7 +84,7 @@ struct meta
{
if (count)
{
- + table->dataMaps.sub_array (start_offset, count)
+ + table->dataMaps.as_array ().sub_array (start_offset, count)
| hb_map (&DataMap::get_tag)
| hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; })
| hb_sink (hb_array (entries, *count))
@@ -119,7 +119,9 @@ struct meta
DEFINE_SIZE_ARRAY (16, dataMaps);
};
-struct meta_accelerator_t : meta::accelerator_t {};
+struct meta_accelerator_t : meta::accelerator_t {
+ meta_accelerator_t (hb_face_t *face) : meta::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc
index 72aeff82d..5b12482b9 100644
--- a/src/hb-ot-metrics.cc
+++ b/src/hb-ot-metrics.cc
@@ -71,12 +71,13 @@ _hb_ot_metrics_get_position_common (hb_font_t *font,
#endif
#define GET_METRIC_X(TABLE, ATTR) \
(face->table.TABLE->has_data () && \
- (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
- face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+ ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
+ face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
#define GET_METRIC_Y(TABLE, ATTR) \
(face->table.TABLE->has_data () && \
- (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
- face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+ ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
+ face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
+
case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
GET_METRIC_Y (hhea, ascender);
@@ -86,9 +87,13 @@ _hb_ot_metrics_get_position_common (hb_font_t *font,
case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) ||
GET_METRIC_Y (hhea, lineGap);
+
+#ifndef HB_NO_VERTICAL
case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender);
case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender);
case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap);
+#endif
+
#undef GET_METRIC_Y
#undef GET_METRIC_X
#undef GET_VAR
@@ -149,18 +154,61 @@ hb_ot_metrics_get_position (hb_font_t *font,
#endif
#define GET_METRIC_X(TABLE, ATTR) \
(face->table.TABLE->has_data () && \
- (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true))
+ ((void) (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR))), true))
#define GET_METRIC_Y(TABLE, ATTR) \
(face->table.TABLE->has_data () && \
- (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true))
+ ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true))
case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent);
case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
- case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise);
- case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: return GET_METRIC_X (hhea, caretSlopeRun);
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
+ case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
+ {
+ unsigned mult = 1u;
+
+ if (font->slant)
+ {
+ unsigned rise = face->table.hhea->caretSlopeRise;
+ unsigned upem = face->get_upem ();
+ mult = (rise && rise < upem) ? hb_min (upem / rise, 256u) : 1u;
+ }
+
+ if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE)
+ {
+ bool ret = GET_METRIC_Y (hhea, caretSlopeRise);
+
+ if (position)
+ *position *= mult;
+
+ return ret;
+ }
+ else
+ {
+ hb_position_t rise = 0;
+
+ if (font->slant && position && GET_METRIC_Y (hhea, caretSlopeRise))
+ rise = *position;
+
+ bool ret = GET_METRIC_X (hhea, caretSlopeRun);
+
+ if (position)
+ {
+ *position *= mult;
+
+ if (font->slant)
+ *position += _hb_roundf (mult * font->slant_xy * rise);
+ }
+
+ return ret;
+ }
+ }
case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset);
+
+#ifndef HB_NO_VERTICAL
case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise);
case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun);
case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: return GET_METRIC_Y (vhea, caretOffset);
+#endif
case HB_OT_METRICS_TAG_X_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sxHeight);
case HB_OT_METRICS_TAG_CAP_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sCapHeight);
case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySubscriptXSize);
@@ -190,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t *font,
}
}
+/**
+ * hb_ot_metrics_get_position_with_fallback:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ * @position: (out) (optional): result of metrics value from the font.
+ *
+ * Fetches metrics value corresponding to @metrics_tag from @font,
+ * and synthesizes a value if it the value is missing in the font.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_metrics_get_position_with_fallback (hb_font_t *font,
+ hb_ot_metrics_tag_t metrics_tag,
+ hb_position_t *position /* OUT */)
+{
+ hb_font_extents_t font_extents;
+ hb_codepoint_t glyph;
+ hb_glyph_extents_t extents;
+
+ if (hb_ot_metrics_get_position (font, metrics_tag, position))
+ {
+ if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE &&
+ metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) ||
+ *position != 0)
+ return;
+ }
+
+ switch (metrics_tag)
+ {
+ case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+ case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+ *position = font_extents.ascender;
+ break;
+
+ case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+ *position = font_extents.ascender;
+ break;
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+ case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+ *position = font_extents.descender;
+ break;
+
+ case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+ *position = font_extents.ascender;
+ break;
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+ *position = font_extents.line_gap;
+ break;
+
+ case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:
+ hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+ *position = font_extents.line_gap;
+ break;
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
+ case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:
+ *position = 1;
+ break;
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
+ case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:
+ *position = 0;
+ break;
+
+ case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:
+ case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:
+ *position = 0;
+ break;
+
+ case HB_OT_METRICS_TAG_X_HEIGHT:
+ if (hb_font_get_nominal_glyph (font, 'x', &glyph) &&
+ hb_font_get_glyph_extents (font, glyph, &extents))
+ *position = extents.y_bearing;
+ else
+ *position = font->y_scale / 2;
+ break;
+
+ case HB_OT_METRICS_TAG_CAP_HEIGHT:
+ if (hb_font_get_nominal_glyph (font, 'O', &glyph) &&
+ hb_font_get_glyph_extents (font, glyph, &extents))
+ *position = extents.height + 2 * extents.y_bearing;
+ else
+ *position = font->y_scale * 2 / 3;
+ break;
+
+ case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:
+ case HB_OT_METRICS_TAG_UNDERLINE_SIZE:
+ *position = font->y_scale / 18;
+ break;
+
+ case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:
+ {
+ hb_position_t ascender;
+ hb_ot_metrics_get_position_with_fallback (font,
+ HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+ &ascender);
+ *position = ascender / 2;
+ }
+ break;
+
+ case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:
+ *position = - font->y_scale / 18;
+ break;
+
+ case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:
+ case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:
+ *position = font->x_scale * 10 / 12;
+ break;
+
+ case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:
+ case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:
+ *position = font->y_scale * 10 / 12;
+ break;
+
+ case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:
+ case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:
+ *position = 0;
+ break;
+
+ case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:
+ case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:
+ *position = font->y_scale / 5;
+ break;
+
+ case _HB_OT_METRICS_TAG_MAX_VALUE:
+ default:
+ *position = 0;
+ break;
+ }
+}
+
#ifndef HB_NO_VAR
/**
* hb_ot_metrics_get_variation:
diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h
index 5841fc8b0..30de50008 100644
--- a/src/hb-ot-metrics.h
+++ b/src/hb-ot-metrics.h
@@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t *font,
hb_ot_metrics_tag_t metrics_tag,
hb_position_t *position /* OUT. May be NULL. */);
+HB_EXTERN void
+hb_ot_metrics_get_position_with_fallback (hb_font_t *font,
+ hb_ot_metrics_tag_t metrics_tag,
+ hb_position_t *position /* OUT */);
+
HB_EXTERN float
hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
diff --git a/src/hb-ot-name-language-static.hh b/src/hb-ot-name-language-static.hh
index c496dc298..0e0f2d632 100644
--- a/src/hb-ot-name-language-static.hh
+++ b/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/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index c17bb4abb..6f4461cc1 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -30,10 +30,55 @@
#include "hb-open-type.hh"
#include "hb-ot-name-language.hh"
#include "hb-aat-layout.hh"
+#include "hb-utf.hh"
namespace OT {
+template <typename in_utf_t, typename out_utf_t>
+inline unsigned int
+hb_ot_name_convert_utf (hb_bytes_t bytes,
+ unsigned int *text_size /* IN/OUT */,
+ typename out_utf_t::codepoint_t *text /* OUT */)
+{
+ unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
+ const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
+ const typename in_utf_t::codepoint_t *src_end = src + src_len;
+
+ typename out_utf_t::codepoint_t *dst = text;
+
+ hb_codepoint_t unicode;
+ const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+ if (text_size && *text_size)
+ {
+ (*text_size)--; /* Save room for NUL-termination. */
+ const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
+
+ while (src < src_end && dst < dst_end)
+ {
+ const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
+ typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
+ if (dst_next == dst)
+ break; /* Out-of-room. */
+
+ dst = dst_next;
+ src = src_next;
+ }
+
+ *text_size = dst - text;
+ *dst = 0; /* NUL-terminate. */
+ }
+
+ /* Accumulate length of rest. */
+ unsigned int dst_len = dst - text;
+ while (src < src_end)
+ {
+ src = in_utf_t::next (src, src_end, &unicode, replacement);
+ dst_len += out_utf_t::encode_len (unicode);
+ }
+ return dst_len;
+}
#define entry_score var.u16[0]
#define entry_index var.u16[1]
@@ -97,12 +142,68 @@ struct NameRecord
return UNSUPPORTED;
}
- NameRecord* copy (hb_serialize_context_t *c, const void *base) const
+ NameRecord* copy (hb_serialize_context_t *c, const void *base
+#ifdef HB_EXPERIMENTAL_API
+ , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+ ) const
{
TRACE_SERIALIZE (this);
+ HB_UNUSED auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+#ifdef HB_EXPERIMENTAL_API
+ hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
+ hb_bytes_t* name_bytes;
+
+ if (name_table_overrides->has (record_ids, &name_bytes)) {
+ hb_bytes_t encoded_bytes = *name_bytes;
+ char *name_str_utf16_be = nullptr;
+
+ if (platformID != 1)
+ {
+ unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
+
+ text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
+ unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+ name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
+ if (!name_str_utf16_be)
+ {
+ c->revert (snap);
+ return_trace (nullptr);
+ }
+ hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
+ (hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
+
+ unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+ if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+ c->revert (snap);
+ hb_free (name_str_utf16_be);
+ return_trace (nullptr);
+ }
+
+ encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
+ }
+ else
+ {
+ // mac platform, copy the UTF-8 string(all ascii characters) as is
+ if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+ c->revert (snap);
+ return_trace (nullptr);
+ }
+ }
+
+ out->offset = 0;
+ c->push ();
+ encoded_bytes.copy (c);
+ c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
+ hb_free (name_str_utf16_be);
+ }
+ else
+#endif
+ {
+ out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+ }
return_trace (out);
}
@@ -156,7 +257,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 +270,19 @@ _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);
+
+ // '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 (!exact && c &&
+ hb_language_matches (b->language, a->language))
+ return 0;
+
+ return c;
}
static int
@@ -178,7 +290,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;
@@ -205,29 +317,61 @@ struct name
hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
- const void *src_string_pool)
+ const void *src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+ , const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
+ , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+ )
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
+ unsigned total_count = it.len ()
+#ifdef HB_EXPERIMENTAL_API
+ + insert_name_records.length
+#endif
+ ;
this->format = 0;
- this->count = it.len ();
+ if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return false;
- NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
+ NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
if (unlikely (!name_records)) return_trace (false);
- hb_array_t<NameRecord> records (name_records, it.len ());
+ hb_array_t<NameRecord> records (name_records, total_count);
for (const NameRecord& record : it)
{
+ hb_memcpy (name_records, &record, NameRecord::static_size);
+ name_records++;
+ }
+
+#ifdef HB_EXPERIMENTAL_API
+ for (unsigned i = 0; i < insert_name_records.length; i++)
+ {
+ const hb_ot_name_record_ids_t& ids = insert_name_records[i];
+ NameRecord record;
+ record.platformID = ids.platform_id;
+ record.encodingID = ids.encoding_id;
+ record.languageID = ids.language_id;
+ record.nameID = ids.name_id;
+ record.length = 0; // handled in NameRecord copy()
+ record.offset = 0;
memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
+#endif
records.qsort ();
- c->copy_all (records, src_string_pool);
+ c->copy_all (records,
+ src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+ , name_table_overrides
+#endif
+ );
hb_free (records.arrayZ);
@@ -245,6 +389,11 @@ struct name
name *name_prime = c->serializer->start_embed<name> ();
if (unlikely (!name_prime)) return_trace (false);
+#ifdef HB_EXPERIMENTAL_API
+ const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
+ c->plan->name_table_overrides;
+#endif
+
auto it =
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
@@ -254,10 +403,48 @@ struct name
(c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
|| namerecord.isUnicode ();
})
+#ifdef HB_EXPERIMENTAL_API
+ | hb_filter ([&] (const NameRecord& namerecord) {
+ if (name_table_overrides->is_empty ())
+ return true;
+ hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
+ namerecord.encodingID,
+ namerecord.languageID,
+ namerecord.nameID);
+
+ hb_bytes_t *p;
+ if (name_table_overrides->has (rec_ids, &p) &&
+ (*p).length == 0)
+ return false;
+ return true;
+ })
+#endif
;
- name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
- return_trace (name_prime->count);
+#ifdef HB_EXPERIMENTAL_API
+ hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
+ if (!name_table_overrides->is_empty ())
+ {
+ if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population ())))
+ return_trace (false);
+ for (const auto& record_ids : name_table_overrides->keys ())
+ {
+ if (name_table_overrides->get (record_ids).length == 0)
+ continue;
+ if (has_name_record_with_ids (record_ids))
+ continue;
+ insert_name_records.push (record_ids);
+ }
+ }
+#endif
+
+ return (name_prime->serialize (c->serializer, it,
+ std::addressof (this + stringOffset)
+#ifdef HB_EXPERIMENTAL_API
+ , insert_name_records
+ , name_table_overrides
+#endif
+ ));
}
bool sanitize_records (hb_sanitize_context_t *c) const
@@ -279,7 +466,7 @@ struct name
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<name> (face);
assert (this->table.get_length () >= this->table->stringOffset);
@@ -288,7 +475,6 @@ struct name
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
this->table->count);
- this->names.init ();
this->names.alloc (all_names.length);
for (unsigned int i = 0; i < all_names.length; i++)
@@ -318,10 +504,8 @@ struct name
}
this->names.resize (j);
}
-
- void fini ()
+ ~accelerator_t ()
{
- this->names.fini ();
this->table.destroy ();
}
@@ -333,7 +517,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;
@@ -359,6 +554,23 @@ struct name
hb_vector_t<hb_ot_name_entry_t> names;
};
+ private:
+ // sometimes NameRecords are not sorted in the font file, so use linear search
+ // here
+ bool has_name_record_with_ids (const hb_ot_name_record_ids_t& record_ids) const
+ {
+ for (const auto& record : nameRecordZ.as_array (count))
+ {
+ if (record.platformID == record_ids.platform_id &&
+ record.encodingID == record_ids.encoding_id &&
+ record.languageID == record_ids.language_id &&
+ record.nameID == record_ids.name_id)
+ return true;
+ }
+ return false;
+ }
+
+ public:
/* We only implement format 0 for now. */
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
@@ -373,7 +585,9 @@ struct name
#undef entry_index
#undef entry_score
-struct name_accelerator_t : name::accelerator_t {};
+struct name_accelerator_t : name::accelerator_t {
+ name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index eff46ef22..6adf1e8fb 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -52,7 +52,7 @@
* array is owned by the @face and should not be modified. It can be
* used as long as @face is alive.
*
- * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries.
+ * Returns: (transfer none) (array length=num_entries): Array of available name entries.
* Since: 2.1.0
**/
const hb_ot_name_entry_t *
@@ -64,52 +64,6 @@ hb_ot_name_list_names (hb_face_t *face,
return (const hb_ot_name_entry_t *) name.names;
}
-
-template <typename in_utf_t, typename out_utf_t>
-static inline unsigned int
-hb_ot_name_convert_utf (hb_bytes_t bytes,
- unsigned int *text_size /* IN/OUT */,
- typename out_utf_t::codepoint_t *text /* OUT */)
-{
- unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
- const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
- const typename in_utf_t::codepoint_t *src_end = src + src_len;
-
- typename out_utf_t::codepoint_t *dst = text;
-
- hb_codepoint_t unicode;
- const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
-
- if (text_size && *text_size)
- {
- (*text_size)--; /* Same room for NUL-termination. */
- const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
-
- while (src < src_end && dst < dst_end)
- {
- const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
- typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
- if (dst_next == dst)
- break; /* Out-of-room. */
-
- dst = dst_next;
- src = src_next;
- }
-
- *text_size = dst - text;
- *dst = 0; /* NUL-terminate. */
- }
-
- /* Accumulate length of rest. */
- unsigned int dst_len = dst - text;
- while (src < src_end)
- {
- src = in_utf_t::next (src, src_end, &unicode, replacement);
- dst_len += out_utf_t::encode_len (unicode);
- }
- return dst_len;
-}
-
template <typename utf_t>
static inline unsigned int
hb_ot_name_get_utf (hb_face_t *face,
@@ -130,10 +84,10 @@ hb_ot_name_get_utf (hb_face_t *face,
hb_bytes_t bytes = name.get_name (idx);
if (width == 2) /* UTF16-BE */
- return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text);
+ return OT::hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text);
if (width == 1) /* ASCII */
- return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
+ return OT::hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
}
if (text_size)
@@ -227,5 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face,
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
}
-
#endif
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index f0035e2f0..5b017d56a 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -166,11 +166,73 @@ struct OS2
}
}
+ float map_wdth_to_widthclass(float width) const
+ {
+ if (width < 50) return 1.0f;
+ if (width > 200) return 9.0f;
+
+ float ratio = (width - 50) / 12.5f;
+ int a = (int) floorf (ratio);
+ int b = (int) ceilf (ratio);
+
+ /* follow this maping:
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
+ */
+ if (b <= 6) // 50-125
+ {
+ if (a == b) return a + 1.0f;
+ }
+ else if (b == 7) // no mapping for 137.5
+ {
+ a = 6;
+ b = 8;
+ }
+ else if (b == 8)
+ {
+ if (a == b) return 8.0f; // 150
+ a = 6;
+ }
+ else
+ {
+ if (a == b && a == 12) return 9.0f; //200
+ b = 12;
+ a = 8;
+ }
+
+ float va = 50 + a * 12.5f;
+ float vb = 50 + b * 12.5f;
+
+ float ret = a + (width - va) / (vb - va);
+ if (a <= 6) ret += 1.0f;
+ return ret;
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
OS2 *os2_prime = c->serializer->embed (this);
if (unlikely (!os2_prime)) return_trace (false);
+
+ if (c->plan->user_axes_location->has (HB_TAG ('w','g','h','t')) &&
+ !c->plan->pinned_at_default)
+ {
+ float weight_class = c->plan->user_axes_location->get (HB_TAG ('w','g','h','t'));
+ if (!c->serializer->check_assign (os2_prime->usWeightClass,
+ roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+
+ if (c->plan->user_axes_location->has (HB_TAG ('w','d','t','h')) &&
+ !c->plan->pinned_at_default)
+ {
+ float width = c->plan->user_axes_location->get (HB_TAG ('w','d','t','h'));
+ if (!c->serializer->check_assign (os2_prime->usWidthClass,
+ roundf (map_wdth_to_widthclass (width)),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+ }
+
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
return_trace (true);
@@ -224,9 +286,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/src/hb-ot-post-table-v2subset.hh b/src/hb-ot-post-table-v2subset.hh
index 94450eb53..951e6395d 100644
--- a/src/hb-ot-post-table-v2subset.hh
+++ b/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);
@@ -76,36 +76,44 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
hb_map_t old_new_index_map, old_gid_new_index_map;
unsigned i = 0;
- post::accelerator_t _post;
- _post.init (c->plan->source);
+ post::accelerator_t _post (c->plan->source);
+ hb_hashmap_t<hb_bytes_t, uint32_t, 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 uint32_t *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);
- int standard_glyph_index = -1;
- for (unsigned i = 0; i < format1_names_length; i++)
+ new_index = glyph_name_to_new_index.get (s);
+ if (new_index == (unsigned)-1)
{
- if (s == format1_names (i))
+ int standard_glyph_index = -1;
+ for (unsigned i = 0; i < format1_names_length; i++)
{
- standard_glyph_index = i;
- break;
+ if (s == format1_names (i))
+ {
+ standard_glyph_index = i;
+ break;
+ }
}
+
+ if (standard_glyph_index == -1)
+ {
+ new_index = 258 + i;
+ i++;
+ }
+ else
+ { new_index = standard_glyph_index; }
+ glyph_name_to_new_index.set (s, new_index);
}
- if (standard_glyph_index == -1)
- {
- new_index = 258 + i;
- i++;
- }
- else
- { new_index = standard_glyph_index; }
old_new_index_map.set (old_index, new_index);
}
old_gid_new_index_map.set (old_gid, new_index);
@@ -121,9 +129,7 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
})
;
- bool ret = serialize (c->serializer, index_iter, &_post);
- _post.fini ();
- return_trace (ret);
+ return_trace (serialize (c->serializer, index_iter, &_post));
}
} /* namespace OT */
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 39de67170..a04b80357 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -84,7 +84,7 @@ struct post
post *post_prime = c->allocate_min<post> ();
if (unlikely (!post_prime)) return_trace (false);
- memcpy (post_prime, this, post::min_size);
+ hb_memcpy (post_prime, this, post::min_size);
if (!glyph_names)
return_trace (c->check_assign (post_prime->version.major, 3,
HB_SERIALIZE_ERROR_INT_OVERFLOW)); // Version 3 does not have any glyph names.
@@ -102,6 +102,14 @@ struct post
if (!serialize (c->serializer, glyph_names))
return_trace (false);
+ if (c->plan->user_axes_location->has (HB_TAG ('s','l','n','t')) &&
+ !c->plan->pinned_at_default)
+ {
+ float italic_angle = c->plan->user_axes_location->get (HB_TAG ('s','l','n','t'));
+ italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
+ post_prime->italicAngle.set_float (italic_angle);
+ }
+
if (glyph_names && version.major == 2)
return_trace (v2X.subset (c));
@@ -111,10 +119,9 @@ struct post
struct accelerator_t
{
friend struct postV2Tail;
- void init (hb_face_t *face)
- {
- index_to_offset.init ();
+ accelerator_t (hb_face_t *face)
+ {
table = hb_sanitize_context_t ().reference_table<post> (face);
unsigned int table_length = table.get_length ();
@@ -132,10 +139,9 @@ struct post
data += 1 + *data)
index_to_offset.push (data - pool);
}
- void fini ()
+ ~accelerator_t ()
{
- index_to_offset.fini ();
- hb_free (gids_sorted_by_name.get ());
+ hb_free (gids_sorted_by_name.get_acquire ());
table.destroy ();
}
@@ -162,7 +168,7 @@ struct post
if (unlikely (!len)) return false;
retry:
- uint16_t *gids = gids_sorted_by_name.get ();
+ uint16_t *gids = gids_sorted_by_name.get_acquire ();
if (unlikely (!gids))
{
@@ -254,9 +260,9 @@ struct post
private:
uint32_t version;
- const Array16Of<HBUINT16> *glyphNameIndex;
+ const Array16Of<HBUINT16> *glyphNameIndex = nullptr;
hb_vector_t<uint32_t> index_to_offset;
- const uint8_t *pool;
+ const uint8_t *pool = nullptr;
hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
};
@@ -265,10 +271,10 @@ struct post
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this) &&
- (version.to_int () == 0x00010000 ||
- (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
- version.to_int () == 0x00030000)));
+ return_trace (c->check_struct (this) &&
+ (version.to_int () == 0x00010000 ||
+ (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
+ version.to_int () == 0x00030000));
}
public:
@@ -276,7 +282,7 @@ struct post
* 0x00020000 for version 2.0
* 0x00025000 for version 2.5 (deprecated)
* 0x00030000 for version 3.0 */
- HBFixed italicAngle; /* Italic angle in counter-clockwise degrees
+ F16DOT16 italicAngle; /* Italic angle in counter-clockwise degrees
* from the vertical. Zero for upright text,
* negative for text that leans to the right
* (forward). */
@@ -307,7 +313,10 @@ struct post
DEFINE_SIZE_MIN (32);
};
-struct post_accelerator_t : post::accelerator_t {};
+struct post_accelerator_t : post::accelerator_t {
+ post_accelerator_t (hb_face_t *face) : post::accelerator_t (face) {}
+};
+
} /* namespace OT */
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
deleted file mode 100644
index 74bf3ca0f..000000000
--- a/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/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
deleted file mode 100644
index 326aa9f96..000000000
--- a/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/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh
deleted file mode 100644
index dcb28a4e8..000000000
--- a/src/hb-ot-shape-complex-indic.hh
+++ /dev/null
@@ -1,430 +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 (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/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh
deleted file mode 100644
index c52f72f39..000000000
--- a/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/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh
deleted file mode 100644
index 35bfbb64d..000000000
--- a/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/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh
deleted file mode 100644
index f4ef33004..000000000
--- a/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/src/hb-ot-shape-complex-myanmar.hh b/src/hb-ot-shape-complex-myanmar.hh
deleted file mode 100644
index 7fbca3878..000000000
--- a/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/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
deleted file mode 100644
index c3920b2cc..000000000
--- a/src/hb-ot-shape-complex-use-machine.hh
+++ /dev/null
@@ -1,576 +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_HVM 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_ZWNJ 14u
-
-
-#line 99 "hb-ot-shape-complex-use-machine.hh"
-static const unsigned char _use_syllable_machine_trans_keys[] = {
- 0u, 51u, 41u, 42u, 42u, 42u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 23u, 48u,
- 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u,
- 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u,
- 11u, 48u, 1u, 48u, 13u, 13u, 4u, 4u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u,
- 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u,
- 24u, 48u, 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u,
- 22u, 48u, 11u, 48u, 1u, 48u, 4u, 4u, 13u, 13u, 1u, 48u, 11u, 48u, 41u, 42u,
- 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, 0
-};
-
-static const char _use_syllable_machine_key_spans[] = {
- 52, 2, 1, 38, 38, 1, 27, 26,
- 24, 23, 22, 2, 1, 25, 25, 25,
- 1, 25, 26, 26, 26, 27, 27, 27,
- 38, 48, 1, 1, 38, 38, 1, 27,
- 26, 24, 23, 22, 2, 1, 25, 25,
- 25, 1, 25, 26, 26, 26, 27, 27,
- 27, 38, 48, 1, 1, 48, 38, 2,
- 1, 5, 3, 4, 3
-};
-
-static const short _use_syllable_machine_index_offsets[] = {
- 0, 53, 56, 58, 97, 136, 138, 166,
- 193, 218, 242, 265, 268, 270, 296, 322,
- 348, 350, 376, 403, 430, 457, 485, 513,
- 541, 580, 629, 631, 633, 672, 711, 713,
- 741, 768, 793, 817, 840, 843, 845, 871,
- 897, 923, 925, 951, 978, 1005, 1032, 1060,
- 1088, 1116, 1155, 1204, 1206, 1208, 1257, 1296,
- 1299, 1301, 1307, 1311, 1316
-};
-
-static const char _use_syllable_machine_indicies[] = {
- 0, 1, 2, 2, 3, 4, 2, 2,
- 2, 2, 2, 5, 6, 7, 2, 2,
- 2, 2, 8, 2, 2, 2, 9, 10,
- 11, 12, 13, 14, 15, 9, 16, 17,
- 18, 19, 20, 21, 2, 22, 23, 24,
- 2, 25, 26, 27, 28, 29, 30, 31,
- 6, 32, 2, 33, 2, 0, 35, 34,
- 35, 34, 37, 38, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 39, 40, 41,
- 42, 43, 44, 45, 39, 46, 1, 47,
- 48, 49, 50, 36, 51, 52, 53, 36,
- 36, 36, 36, 54, 55, 56, 57, 38,
- 36, 37, 38, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 39, 40, 41, 42,
- 43, 44, 45, 39, 46, 47, 47, 48,
- 49, 50, 36, 51, 52, 53, 36, 36,
- 36, 36, 54, 55, 56, 57, 38, 36,
- 37, 58, 39, 40, 41, 42, 43, 36,
- 36, 36, 36, 36, 36, 48, 49, 50,
- 36, 51, 52, 53, 36, 36, 36, 36,
- 40, 55, 56, 57, 59, 36, 40, 41,
- 42, 43, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 51, 52, 53, 36,
- 36, 36, 36, 36, 55, 56, 57, 59,
- 36, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 55, 56,
- 57, 36, 42, 43, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 55, 56,
- 57, 36, 43, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 55, 56, 57,
- 36, 55, 56, 36, 56, 36, 41, 42,
- 43, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 51, 52, 53, 36, 36,
- 36, 36, 36, 55, 56, 57, 59, 36,
- 41, 42, 43, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 52, 53,
- 36, 36, 36, 36, 36, 55, 56, 57,
- 59, 36, 41, 42, 43, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 53, 36, 36, 36, 36, 36, 55,
- 56, 57, 59, 36, 61, 60, 41, 42,
- 43, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 55, 56, 57, 59, 36,
- 40, 41, 42, 43, 36, 36, 36, 36,
- 36, 36, 48, 49, 50, 36, 51, 52,
- 53, 36, 36, 36, 36, 40, 55, 56,
- 57, 59, 36, 40, 41, 42, 43, 36,
- 36, 36, 36, 36, 36, 36, 49, 50,
- 36, 51, 52, 53, 36, 36, 36, 36,
- 40, 55, 56, 57, 59, 36, 40, 41,
- 42, 43, 36, 36, 36, 36, 36, 36,
- 36, 36, 50, 36, 51, 52, 53, 36,
- 36, 36, 36, 40, 55, 56, 57, 59,
- 36, 39, 40, 41, 42, 43, 36, 45,
- 39, 36, 36, 36, 48, 49, 50, 36,
- 51, 52, 53, 36, 36, 36, 36, 40,
- 55, 56, 57, 59, 36, 39, 40, 41,
- 42, 43, 36, 36, 39, 36, 36, 36,
- 48, 49, 50, 36, 51, 52, 53, 36,
- 36, 36, 36, 40, 55, 56, 57, 59,
- 36, 39, 40, 41, 42, 43, 44, 45,
- 39, 36, 36, 36, 48, 49, 50, 36,
- 51, 52, 53, 36, 36, 36, 36, 40,
- 55, 56, 57, 59, 36, 37, 38, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 39, 40, 41, 42, 43, 44, 45, 39,
- 46, 36, 47, 48, 49, 50, 36, 51,
- 52, 53, 36, 36, 36, 36, 54, 55,
- 56, 57, 38, 36, 37, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 40, 41, 42, 43, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58,
- 51, 52, 53, 58, 58, 58, 58, 58,
- 55, 56, 57, 59, 58, 63, 62, 3,
- 64, 37, 38, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 39, 40, 41, 42,
- 43, 44, 45, 39, 46, 1, 47, 48,
- 49, 50, 36, 51, 52, 53, 36, 0,
- 35, 36, 54, 55, 56, 57, 38, 36,
- 5, 6, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 9, 10, 11, 12, 13,
- 14, 15, 9, 16, 18, 18, 19, 20,
- 21, 65, 22, 23, 24, 65, 65, 65,
- 65, 28, 29, 30, 31, 6, 65, 5,
- 65, 9, 10, 11, 12, 13, 65, 65,
- 65, 65, 65, 65, 19, 20, 21, 65,
- 22, 23, 24, 65, 65, 65, 65, 10,
- 29, 30, 31, 66, 65, 10, 11, 12,
- 13, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 22, 23, 24, 65, 65,
- 65, 65, 65, 29, 30, 31, 66, 65,
- 11, 12, 13, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 29, 30, 31,
- 65, 12, 13, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 29, 30, 31,
- 65, 13, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 29, 30, 31, 65,
- 29, 30, 65, 30, 65, 11, 12, 13,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 22, 23, 24, 65, 65, 65,
- 65, 65, 29, 30, 31, 66, 65, 11,
- 12, 13, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 23, 24, 65,
- 65, 65, 65, 65, 29, 30, 31, 66,
- 65, 11, 12, 13, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 24, 65, 65, 65, 65, 65, 29, 30,
- 31, 66, 65, 67, 65, 11, 12, 13,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 29, 30, 31, 66, 65, 10,
- 11, 12, 13, 65, 65, 65, 65, 65,
- 65, 19, 20, 21, 65, 22, 23, 24,
- 65, 65, 65, 65, 10, 29, 30, 31,
- 66, 65, 10, 11, 12, 13, 65, 65,
- 65, 65, 65, 65, 65, 20, 21, 65,
- 22, 23, 24, 65, 65, 65, 65, 10,
- 29, 30, 31, 66, 65, 10, 11, 12,
- 13, 65, 65, 65, 65, 65, 65, 65,
- 65, 21, 65, 22, 23, 24, 65, 65,
- 65, 65, 10, 29, 30, 31, 66, 65,
- 9, 10, 11, 12, 13, 65, 15, 9,
- 65, 65, 65, 19, 20, 21, 65, 22,
- 23, 24, 65, 65, 65, 65, 10, 29,
- 30, 31, 66, 65, 9, 10, 11, 12,
- 13, 65, 65, 9, 65, 65, 65, 19,
- 20, 21, 65, 22, 23, 24, 65, 65,
- 65, 65, 10, 29, 30, 31, 66, 65,
- 9, 10, 11, 12, 13, 14, 15, 9,
- 65, 65, 65, 19, 20, 21, 65, 22,
- 23, 24, 65, 65, 65, 65, 10, 29,
- 30, 31, 66, 65, 5, 6, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 9,
- 10, 11, 12, 13, 14, 15, 9, 16,
- 65, 18, 19, 20, 21, 65, 22, 23,
- 24, 65, 65, 65, 65, 28, 29, 30,
- 31, 6, 65, 5, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 10, 11, 12, 13, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 22,
- 23, 24, 65, 65, 65, 65, 65, 29,
- 30, 31, 66, 65, 68, 65, 7, 65,
- 1, 65, 65, 65, 1, 65, 65, 65,
- 65, 65, 5, 6, 7, 65, 65, 65,
- 65, 65, 65, 65, 65, 9, 10, 11,
- 12, 13, 14, 15, 9, 16, 17, 18,
- 19, 20, 21, 65, 22, 23, 24, 65,
- 25, 26, 65, 28, 29, 30, 31, 6,
- 65, 5, 6, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 9, 10, 11, 12,
- 13, 14, 15, 9, 16, 17, 18, 19,
- 20, 21, 65, 22, 23, 24, 65, 65,
- 65, 65, 28, 29, 30, 31, 6, 65,
- 25, 26, 65, 26, 65, 1, 69, 69,
- 69, 1, 69, 71, 70, 32, 70, 32,
- 71, 70, 71, 70, 32, 70, 33, 70,
- 0
-};
-
-static const char _use_syllable_machine_trans_targs[] = {
- 1, 3, 0, 26, 28, 29, 30, 51,
- 53, 31, 32, 33, 34, 35, 46, 47,
- 48, 54, 49, 43, 44, 45, 38, 39,
- 40, 55, 56, 57, 50, 36, 37, 0,
- 58, 60, 0, 2, 0, 4, 5, 6,
- 7, 8, 9, 10, 21, 22, 23, 24,
- 18, 19, 20, 13, 14, 15, 25, 11,
- 12, 0, 0, 16, 0, 17, 0, 27,
- 0, 0, 41, 42, 52, 0, 0, 59
-};
-
-static const char _use_syllable_machine_trans_actions[] = {
- 0, 0, 3, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 4,
- 0, 0, 5, 0, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 7, 8, 0, 9, 0, 10, 0,
- 11, 12, 0, 0, 0, 13, 14, 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
-};
-
-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
-};
-
-static const short _use_syllable_machine_eof_trans[] = {
- 0, 35, 35, 37, 37, 59, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 61, 37, 37, 37, 37, 37, 37, 37,
- 37, 59, 63, 65, 37, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 70, 71, 71, 71
-};
-
-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 179 "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) : it (o.it) {}
-
- 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)
- { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
- void operator = (const machine_index_t& o) { *this = (*o.it).first; }
- bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
- bool operator != (const machine_index_t& o) const { return !(*this == o); }
-
- private:
- Iter it;
-};
-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) && _hb_glyph_info_is_default_ignorable (&i)); }
-
-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 453 "hb-ot-shape-complex-use-machine.hh"
- {
- cs = use_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 263 "hb-ot-shape-complex-use-machine.rl"
-
-
- unsigned int syllable_serial = 1;
-
-#line 466 "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 480 "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 7:
-#line 169 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (use_standard_cluster); }}
- break;
- case 4:
-#line 174 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (use_broken_cluster); }}
- break;
- case 3:
-#line 175 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (use_non_cluster); }}
- break;
- case 8:
-#line 167 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
- break;
- case 9:
-#line 168 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
- break;
- case 6:
-#line 169 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_standard_cluster); }}
- break;
- case 11:
-#line 170 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
- break;
- case 10:
-#line 171 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_numeral_cluster); }}
- break;
- case 5:
-#line 172 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_symbol_cluster); }}
- break;
- case 14:
-#line 173 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
- break;
- case 12:
-#line 174 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_broken_cluster); }}
- break;
- case 13:
-#line 175 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (use_non_cluster); }}
- break;
-#line 546 "hb-ot-shape-complex-use-machine.hh"
- }
-
-_again:
- switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 1:
-#line 1 "NONE"
- {ts = 0;}
- break;
-#line 555 "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 268 "hb-ot-shape-complex-use-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-use-table.hh b/src/hb-ot-shape-complex-use-table.hh
deleted file mode 100644
index 7a3a995c8..000000000
--- a/src/hb-ot-shape-complex-use-table.hh
+++ /dev/null
@@ -1,1283 +0,0 @@
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.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]
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # DerivedCoreProperties-14.0.0.txt
- * # Date: 2021-08-12, 23:12:53 GMT
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
- * # Override values For Indic_Syllabic_Category
- * # Not derivable
- * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
- * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
- * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
- * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
- * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
- * # Override values For Indic_Positional_Category
- * # Not derivable
- * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
- * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
- * # Ammended for Unicode 10.0 by Andrew Glass 2018-09-21
- * # Updated for L2/19-083 by Andrew Glass 2019-05-06
- * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
- * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
- * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
- * UnicodeData.txt does not have a header.
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-use-machine.hh"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-#define B USE(B) /* BASE */
-#define CGJ USE(CGJ) /* CGJ */
-#define CS USE(CS) /* CONS_WITH_STACKER */
-#define G USE(G) /* HIEROGLYPH */
-#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 J USE(J) /* HIEROGLYPH_JOINER */
-#define N USE(N) /* BASE_NUM */
-#define O USE(O) /* OTHER */
-#define R USE(R) /* REPHA */
-#define SB USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
-#define SE USE(SE) /* HIEROGLYPH_SEGMENT_END */
-#define SUB USE(SUB) /* CONS_SUB */
-#define Sk USE(Sk) /* SAKOT */
-#define ZWNJ USE(ZWNJ) /* ZWNJ */
-#define CMAbv USE(CMAbv)
-#define CMBlw USE(CMBlw)
-#define FAbv USE(FAbv)
-#define FBlw USE(FBlw)
-#define FPst USE(FPst)
-#define FMAbv USE(FMAbv)
-#define FMBlw USE(FMBlw)
-#define FMPst USE(FMPst)
-#define MAbv USE(MAbv)
-#define MBlw USE(MBlw)
-#define MPst USE(MPst)
-#define MPre USE(MPre)
-#define SMAbv USE(SMAbv)
-#define SMBlw USE(SMBlw)
-#define VAbv USE(VAbv)
-#define VBlw USE(VBlw)
-#define VPst USE(VPst)
-#define VPre USE(VPre)
-#define VMAbv USE(VMAbv)
-#define VMBlw USE(VMBlw)
-#define VMPst USE(VMPst)
-#define VMPre USE(VMPre)
-#pragma GCC diagnostic pop
-
-static const uint8_t use_table[] = {
-
-
-#define use_offset_0x0028u 0
-
-
- /* Basic Latin */
- O, O, O, O, O, GB, O, O,
- /* 0030 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x00a0u 24
-
-
- /* Latin-1 Supplement */
-
- /* 00A0 */ GB, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 00B0 */ O, O, FMPst, FMPst, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 00C0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 00D0 */ O, O, O, O, O, O, O, GB,
-
-#define use_offset_0x0348u 80
-
-
- /* Combining Diacritical Marks */
- O, O, O, O, O, O, O, CGJ,
-
-#define use_offset_0x0640u 88
-
-
- /* Arabic */
-
- /* 0640 */ B, O, O, O, O, O, O, O,
-
-#define use_offset_0x07c8u 96
-
-
- /* NKo */
- O, O, B, B, B, B, B, B,
- /* 07D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 07E0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
- /* 07F0 */ VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, O, O, O, B, O, O, VMAbv, O, O,
-
-#define use_offset_0x0840u 152
-
-
- /* Mandaic */
-
- /* 0840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0850 */ B, B, B, B, B, B, B, B, B, CMBlw, CMBlw, CMBlw, O, O, O, O,
-
-#define use_offset_0x0900u 184
-
-
- /* Devanagari */
-
- /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0930 */ B, B, B, B, B, B, B, B, B, B, VAbv, VPst, CMBlw, B, VPst, VPre,
- /* 0940 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst, H, VPre, VPst,
- /* 0950 */ O, VMAbv, VMBlw, O, O, VAbv, VBlw, VBlw, B, B, B, B, B, B, B, B,
- /* 0960 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0970 */ O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
-
- /* Bengali */
-
- /* 0980 */ GB, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
- /* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
- /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
- /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B,
- /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FMAbv, O,
-
- /* Gurmukhi */
-
- /* 0A00 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, O, O, O, O, B,
- /* 0A10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0A20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 0A30 */ B, O, B, B, O, B, B, O, B, B, O, O, CMBlw, O, VPst, VPre,
- /* 0A40 */ VPst, VBlw, VBlw, O, O, O, O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O,
- /* 0A50 */ O, VMBlw, O, O, O, O, O, O, O, B, B, B, B, O, B, O,
- /* 0A60 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0A70 */ VMAbv, CMAbv, GB, GB, O, MBlw, O, O, O, O, O, O, O, O, O, O,
-
- /* Gujarati */
-
- /* 0A80 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, B, O, B,
- /* 0A90 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0AA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 0AB0 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
- /* 0AC0 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H, O, O,
- /* 0AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 0AE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0AF0 */ O, O, O, O, O, O, O, O, O, B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv,
-
- /* Oriya */
-
- /* 0B00 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
- /* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
- /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
- /* 0B50 */ O, O, O, O, O, VAbv, VAbv, VAbv, O, O, O, O, B, B, O, B,
- /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Tamil */
-
- /* 0B80 */ O, O, VMAbv, O, O, B, B, B, B, B, B, O, O, O, B, B,
- /* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B,
- /* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B,
- /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst,
- /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O,
- /* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O,
- /* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Telugu */
-
- /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, VMAbv, B, B, B, B, B, B, B, B, O, B, B,
- /* 0C10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0C20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 0C30 */ B, B, B, B, B, B, B, B, B, B, O, O, CMBlw, B, VAbv, VAbv,
- /* 0C40 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
- /* 0C50 */ O, O, O, O, O, VAbv, VBlw, O, B, B, B, O, O, O, O, O,
- /* 0C60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0C70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Kannada */
-
- /* 0C80 */ B, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B,
- /* 0C90 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0CA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 0CB0 */ B, B, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
- /* 0CC0 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
- /* 0CD0 */ O, O, O, O, O, VPst, VPst, O, O, O, O, O, O, O, B, O,
- /* 0CE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0CF0 */ O, CS, CS, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Malayalam */
-
- /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst, B, B, B, B, B, B, B, B, B, O, B, B,
- /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst,
- /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O,
- /* 0D50 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, B,
- /* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0D70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Sinhala */
-
- /* 0D80 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, B, B, B,
- /* 0D90 */ B, B, B, B, B, B, B, O, O, O, B, B, B, B, B, B,
- /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O,
- /* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst,
- /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst,
- /* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0DF0 */ O, O, VPst, VPst, O, O, O, O,
-
-#define use_offset_0x0f00u 1456
-
-
- /* Tibetan */
-
- /* 0F00 */ B, B, O, O, B, B, B, O, O, O, O, O, O, O, O, O,
- /* 0F10 */ O, O, O, O, O, O, O, O, VBlw, VBlw, O, O, O, O, O, O,
- /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0F30 */ B, B, B, B, O, FBlw, O, FBlw, O, CMAbv, O, O, O, O, VPst, VPre,
- /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B,
- /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
- /* 0F70 */ O, CMBlw, VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, O,
- /* 0F80 */ VBlw, VAbv, VMAbv, VMAbv, VBlw, O, VMAbv, VMAbv, B, B, B, B, B, SUB, SUB, SUB,
- /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
- /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
- /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O,
- /* 0FC0 */ O, O, O, O, O, O, FBlw, O,
-
-#define use_offset_0x1000u 1656
-
-
- /* Myanmar */
-
- /* 1000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1020 */ B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VAbv, VAbv, VBlw,
- /* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, H, VAbv, MPst, MPre, MBlw, MBlw, B,
- /* 1040 */ B, B, B, B, B, B, B, B, B, B, O, GB, O, O, GB, O,
- /* 1050 */ B, B, B, B, B, B, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw,
- /* 1060 */ MBlw, B, VPst, VMPst, VMPst, B, B, VPst, VPst, VMPst, VMPst, VMPst, VMPst, VMPst, B, B,
- /* 1070 */ B, VAbv, VAbv, VAbv, VAbv, B, B, B, B, B, B, B, B, B, B, B,
- /* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst,
- /* 1090 */ B, B, B, B, B, B, B, B, B, B, VMPst, VMPst, VPst, VAbv, O, O,
-
-#define use_offset_0x1700u 1816
-
-
- /* Tagalog */
-
- /* 1700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1710 */ B, B, VAbv, VBlw, VBlw, VPst, O, O, O, O, O, O, O, O, O, B,
-
- /* Hanunoo */
-
- /* 1720 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1730 */ B, B, VAbv, VBlw, VPst, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Buhid */
-
- /* 1740 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1750 */ B, B, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Tagbanwa */
-
- /* 1760 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, B, B,
- /* 1770 */ B, O, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Khmer */
-
- /* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 17B0 */ B, B, B, B, CGJ, CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
- /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FMAbv, FAbv, CMAbv, FMAbv, VMAbv,
- /* 17D0 */ FMAbv, VAbv, H, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, O, O,
- /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
- /* 17F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Mongolian */
-
- /* 1800 */ B, O, O, O, O, O, O, B, O, O, B, CGJ, CGJ, CGJ, O, CGJ,
- /* 1810 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 1820 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1830 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1850 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1860 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1870 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
- /* 1880 */ GB, GB, GB, GB, GB, CMAbv, CMAbv, B, B, B, B, B, B, B, B, B,
- /* 1890 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18A0 */ B, B, B, B, B, B, B, B, B, CMBlw, B, O, O, O, O, O,
-
-#define use_offset_0x1900u 2248
-
-
- /* Limbu */
-
- /* 1900 */ GB, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O,
- /* 1920 */ VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, O, O, O, O,
- /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VMAbv, FMBlw, O, O, O, O,
- /* 1940 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
-
- /* Tai Le */
-
- /* 1950 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1960 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, O,
- /* 1970 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O,
-
- /* New Tai Lue */
-
- /* 1980 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 19A0 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
- /* 19B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 19C0 */ B, B, B, B, B, B, B, B, VMPst, VMPst, O, O, O, O, O, O,
- /* 19D0 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O,
- /* 19E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 19F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Buginese */
-
- /* 1A00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1A10 */ B, B, B, B, B, B, B, VAbv, VAbv, VPre, VPst, VAbv, O, O, O, O,
-
- /* Tai Tham */
-
- /* 1A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1A30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1A50 */ B, B, B, B, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, O,
- /* 1A60 */ Sk, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre,
- /* 1A70 */ VPre, VPre, VPre, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VAbv, VMAbv, VMAbv, O, O, VMBlw,
- /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
- /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x1b00u 2664
-
-
- /* Balinese */
-
- /* 1B00 */ VMAbv, VMAbv, VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B,
- /* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre,
- /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, B, O, O, O,
- /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, GB, GB, O, O, GB,
- /* 1B60 */ O, O, GB, O, O, O, O, O, GB, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
- /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Sundanese */
-
- /* 1B80 */ VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, H, SUB, SUB, B, B,
- /* 1BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
-
- /* Batak */
-
- /* 1BC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BE0 */ B, B, B, B, B, B, CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv,
- /* 1BF0 */ FAbv, FAbv, CMBlw, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Lepcha */
-
- /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv,
- /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, O, O, O, O, O, O, O, O,
- /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B,
-
-#define use_offset_0x1cd0u 3000
-
-
- /* Vedic Extensions */
-
- /* 1CD0 */ VMAbv, VMAbv, VMAbv, O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
- /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O,
- /* 1CF0 */ O, O, O, O, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, GB, O, O, O, O, O,
-
-#define use_offset_0x1df8u 3048
-
-
- /* Combining Diacritical Marks Supplement */
- O, O, O, FMAbv, O, O, O, O,
-
-#define use_offset_0x2008u 3056
-
-
- /* General Punctuation */
- O, O, O, O, ZWNJ, CGJ, O, O,
- /* 2010 */ GB, GB, GB, GB, GB, O, O, O,
-
-#define use_offset_0x2070u 3072
-
-
- /* Superscripts and Subscripts */
-
- /* 2070 */ O, O, O, O, FMPst, O, O, O, O, O, O, O, O, O, O, O,
- /* 2080 */ O, O, FMPst, FMPst, FMPst, O, O, O,
-
-#define use_offset_0x20f0u 3096
-
-
- /* Combining Diacritical Marks for Symbols */
-
- /* 20F0 */ VMAbv, O, O, O, O, O, O, O,
-
-#define use_offset_0x25c8u 3104
-
-
- /* Geometric Shapes */
- O, O, O, O, B, O, O, O,
-
-#define use_offset_0x2d30u 3112
-
-
- /* Tifinagh */
-
- /* 2D30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 2D40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 2D50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 2D60 */ B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, B,
- /* 2D70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, H,
-
-#define use_offset_0xa800u 3192
-
-
- /* Syloti Nagri */
-
- /* A800 */ B, B, VAbv, B, B, B, H, B, B, B, B, VMAbv, B, B, B, B,
- /* A810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, VBlw, O, O, O,
- /* A830 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Phags-pa */
-
- /* A840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A850 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A860 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A870 */ B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Saurashtra */
-
- /* A880 */ VMPst, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A890 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A8A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A8B0 */ B, B, B, B, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst,
- /* A8C0 */ VPst, VPst, VPst, VPst, H, VMAbv, O, O, O, O, O, O, O, O, O, O,
- /* A8D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
- /* Devanagari Extended */
-
- /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
- /* A8F0 */ VMAbv, VMAbv, B, B, O, O, O, O, O, O, O, O, O, O, B, VAbv,
-
- /* Kayah Li */
-
- /* A900 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A920 */ B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VAbv, VMBlw, VMBlw, VMBlw, O, O,
-
- /* Rejang */
-
- /* A930 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A940 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv,
- /* A950 */ FAbv, FAbv, FPst, VPst, O, O, O, O, O, O, O, O, O, O, O, O,
- /* A960 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* A970 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Javanese */
-
- /* A980 */ VMAbv, VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A9A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, MBlw, MPst, MBlw,
- /* A9C0 */ H, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* A9D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
- /* Myanmar Extended-B */
-
- /* A9E0 */ B, B, B, B, B, VAbv, O, B, B, B, B, B, B, B, B, B,
- /* A9F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O,
-
- /* Cham */
-
- /* AA00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AA10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AA20 */ B, B, B, B, B, B, B, B, B, VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre,
- /* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MAbv, MBlw, O, O, O, O, O, O, O, O, O,
- /* AA40 */ B, B, B, FAbv, B, B, B, B, B, B, B, B, FAbv, FPst, O, O,
- /* AA50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
- /* Myanmar Extended-A */
-
- /* AA60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AA70 */ O, B, B, B, GB, GB, GB, O, O, O, B, VMPst, VMAbv, VMPst, B, B,
-
- /* Tai Viet */
-
- /* AA80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AA90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AAA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AAB0 */ VAbv, B, VAbv, VAbv, VBlw, B, B, VAbv, VAbv, B, B, B, B, B, VAbv, VMAbv,
- /* AAC0 */ B, VMAbv, B, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* AAD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Meetei Mayek Extensions */
-
- /* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
- /* AAF0 */ O, O, O, O, O, VMPst, H, O,
-
-#define use_offset_0xabc0u 3952
-
-
- /* Meetei Mayek */
-
- /* ABC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* ABD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O,
- /* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0xfe00u 4016
-
-
- /* Variation Selectors */
-
- /* FE00 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
-
-#define use_offset_0x10570u 4032
-
-
- /* Vithkuqi */
-
- /* 10570 */ B, B, B, B, B, B, B, B, B, B, B, O, B, B, B, B,
- /* 10580 */ B, B, B, B, B, B, B, B, B, B, B, O, B, B, B, B,
- /* 10590 */ B, B, B, O, B, B, O, B, B, B, B, B, B, B, B, B,
- /* 105A0 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 105B0 */ B, B, O, B, B, B, B, B, B, B, O, B, B, O, O, O,
-
-#define use_offset_0x10a00u 4112
-
-
- /* Kharoshthi */
-
- /* 10A00 */ B, VBlw, VBlw, VBlw, O, VAbv, VBlw, O, O, O, O, O, VPst, VMBlw, VMBlw, VMAbv,
- /* 10A10 */ B, B, B, B, O, B, B, B, O, B, B, B, B, B, B, B,
- /* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10A30 */ B, B, B, B, B, B, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H,
- /* 10A40 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
-
-#define use_offset_0x10ac0u 4192
-
-
- /* Manichaean */
-
- /* 10AC0 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B,
- /* 10AD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10AE0 */ B, B, B, B, B, CMBlw, CMBlw, O, O, O, O, B, B, B, B, B,
-
-#define use_offset_0x10b80u 4240
-
-
- /* Psalter Pahlavi */
-
- /* 10B80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10B90 */ B, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 10BA0 */ O, O, O, O, O, O, O, O, O, B, B, B, B, B, B, O,
-
-#define use_offset_0x10d00u 4288
-
-
- /* Hanifi Rohingya */
-
- /* 10D00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10D10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10D20 */ B, B, B, B, VMAbv, VMAbv, VMAbv, CMAbv, O, O, O, O, O, O, O, O,
- /* 10D30 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x10e80u 4352
-
-
- /* Yezidi */
-
- /* 10E80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10E90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10EA0 */ B, B, B, B, B, B, B, B, B, B, O, VAbv, VAbv, O, O, O,
- /* 10EB0 */ B, B, O, O, O, O, O, O,
-
-#define use_offset_0x10f30u 4408
-
-
- /* Sogdian */
-
- /* 10F30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10F40 */ B, B, B, B, B, B, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,
- /* 10F50 */ VMBlw, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O,
- /* 10F60 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Old Uyghur */
-
- /* 10F70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 10F80 */ B, B, CMBlw, CMBlw, CMBlw, CMBlw, O, O, O, O, O, O, O, O, O, O,
- /* 10F90 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 10FA0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Chorasmian */
-
- /* 10FB0 */ B, O, B, B, B, B, B, O, B, B, B, B, B, B, B, B,
- /* 10FC0 */ O, B, B, B, B, O, O, O, O, B, B, B, O, O, O, O,
- /* 10FD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 10FE0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 10FF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Brahmi */
-
- /* 11000 */ VMPst, VMAbv, VMPst, CS, CS, B, B, B, B, B, B, B, B, B, B, B,
- /* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,
- /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O,
- /* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
- /* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B,
- /* 11070 */ VAbv, B, B, VAbv, VAbv, B, O, O, O, O, O, O, O, O, O, HN,
-
- /* Kaithi */
-
- /* 11080 */ VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11090 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O,
- /* 110C0 */ O, O, VBlw, O, O, O, O, O,
-
-#define use_offset_0x11100u 4816
-
-
- /* Chakma */
-
- /* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv,
- /* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, O, B, B, B, B, B, B, B, B, B, B,
- /* 11140 */ O, O, O, O, B, VPst, VPst, B, O, O, O, O, O, O, O, O,
-
- /* Mahajani */
-
- /* 11150 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11160 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11170 */ B, B, B, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Sharada */
-
- /* 11180 */ VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,
- /* 111C0 */ H, B, R, R, O, O, O, O, GB, FMBlw, CMBlw, VAbv, VBlw, O, VPre, VMAbv,
- /* 111D0 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O,
-
- /* Sinhala Archaic Numbers */
-
- /* 111E0 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 111F0 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Khojki */
-
- /* 11200 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11210 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw,
- /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O,
-
-#define use_offset_0x11280u 5136
-
-
- /* Multani */
-
- /* 11280 */ B, B, B, B, B, B, B, O, B, O, B, B, B, B, O, B,
- /* 11290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, B,
- /* 112A0 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
-
- /* Khudawadi */
-
- /* 112B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 112C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 112D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv,
- /* 112E0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, CMBlw, VBlw, O, O, O, O, O,
- /* 112F0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
- /* Grantha */
-
- /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv, O, B, B, B, B, B, B, B, B, O, O, B,
- /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst,
- /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, HVM, O, O,
- /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B,
- /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
- /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
-
-#define use_offset_0x11400u 5384
-
-
- /* Newa */
-
- /* 11400 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11410 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11430 */ B, B, B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv,
- /* 11440 */ VPst, VPst, H, VMAbv, VMAbv, VMPst, CMBlw, B, O, O, O, O, O, O, O, O,
- /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, FMAbv, B,
- /* 11460 */ CS, CS, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 11470 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Tirhuta */
-
- /* 11480 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv,
- /* 114C0 */ VMAbv, VMAbv, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O,
- /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x11580u 5608
-
-
- /* Siddham */
-
- /* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
- /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H,
- /* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O,
- /* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 115F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Modi */
-
- /* 11600 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11610 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11620 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11630 */ VPst, VPst, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPst, VPst, VMAbv, VMPst, H,
- /* 11640 */ VAbv, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 11650 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
- /* 11660 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 11670 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Takri */
-
- /* 11680 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11690 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 116A0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMPst, VAbv, VPre, VPst,
- /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, B, O, O, O, O, O, O, O,
- /* 116C0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
- /* 116D0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 116E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 116F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Ahom */
-
- /* 11700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11710 */ B, B, B, B, B, B, B, B, B, B, B, O, O, MBlw, MPre, MAbv,
- /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
- /* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
- /* 11740 */ B, B, B, B, B, B, B, O,
-
-#define use_offset_0x11800u 6064
-
-
- /* Dogra */
-
- /* 11800 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw,
- /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O,
-
-#define use_offset_0x11900u 6128
-
-
- /* Dives Akuru */
-
- /* 11900 */ B, B, B, B, B, B, B, O, O, B, O, O, B, B, B, B,
- /* 11910 */ B, B, B, B, O, B, B, O, B, B, B, B, B, B, B, B,
- /* 11920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, O, VPre, VPre, O, O, VMAbv, VMAbv, VPst, H, R,
- /* 11940 */ MPst, R, MPst, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 11950 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x119a0u 6224
-
-
- /* Nandinagari */
-
- /* 119A0 */ B, B, B, B, B, B, B, B, O, O, B, B, B, B, B, B,
- /* 119B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 119C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 119D0 */ B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VAbv, VAbv, VPst, VPst, VMPst, VMPst,
- /* 119E0 */ H, B, O, O, VPre, O, O, O, O, O, O, O, O, O, O, O,
- /* 119F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Zanabazar Square */
-
- /* 11A00 */ B, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, B, B, B, B, B,
- /* 11A10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11A30 */ B, B, B, FMBlw, VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst, R, MBlw, MBlw, MBlw, MBlw, GB,
- /* 11A40 */ O, O, O, O, O, GB, O, H, O, O, O, O, O, O, O, O,
-
- /* Soyombo */
-
- /* 11A50 */ B, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VBlw, VBlw, VBlw, B, B, B, B,
- /* 11A60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11A70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11A80 */ B, B, B, B, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
- /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O,
-
-#define use_offset_0x11c00u 6480
-
-
- /* Bhaiksuki */
-
- /* 11C00 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
- /* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
- /* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H,
- /* 11C40 */ B, O, O, O, GB, GB, O, O, O, O, O, O, O, O, O, O,
- /* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
-
- /* Marchen */
-
- /* 11C70 */ O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11C80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11C90 */ O, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
- /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
- /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O,
-
-#define use_offset_0x11d00u 6664
-
-
- /* Masaram Gondi */
-
- /* 11D00 */ B, B, B, B, B, B, B, O, B, B, O, B, B, B, B, B,
- /* 11D10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11D30 */ B, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, O, O, O, VAbv, O, VAbv, VAbv, O, VAbv,
- /* 11D40 */ VMAbv, VMAbv, CMBlw, VAbv, VBlw, H, R, MBlw, O, O, O, O, O, O, O, O,
- /* 11D50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
- /* Gunjala Gondi */
-
- /* 11D60 */ B, B, B, B, B, B, O, B, B, O, B, B, B, B, B, B,
- /* 11D70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11D80 */ B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VPst, VPst, O,
- /* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O,
- /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x11ee0u 6840
-
-
- /* Makasar */
-
- /* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O,
-
-#define use_offset_0x13000u 6864
-
-
- /* Egyptian Hieroglyphs */
-
- /* 13000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13030 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13040 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13050 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13060 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13070 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13080 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13090 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130E0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 130F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13100 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13120 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13130 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13140 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13150 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13160 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13170 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13180 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131E0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 131F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13200 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13210 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13220 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13230 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13240 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13250 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13260 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13270 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13280 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132E0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 132F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13300 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13310 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13320 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13330 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13340 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13350 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13360 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13370 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13380 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13390 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133E0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 133F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13400 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13410 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 13420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O,
-
- /* Egyptian Hieroglyph Format Controls */
-
- /* 13430 */ H, H, H, H, H, H, H, B, B, O, O, O, O, O, O, O,
-
-#define use_offset_0x16ac0u 7952
-
-
- /* Tangsa */
-
- /* 16AC0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
- /* 16AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 16AE0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 16AF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Pahawh Hmong */
-
- /* 16B00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16B30 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O,
-
-#define use_offset_0x16f00u 8072
-
-
- /* Miao */
-
- /* 16F00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16F10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16F30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 16F40 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, CMBlw,
- /* 16F50 */ O, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw,
- /* 16F60 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw,
- /* 16F70 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw,
- /* 16F80 */ VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, O, O, O, O, O, O, O, VMBlw,
- /* 16F90 */ VMBlw, VMBlw, VMBlw, O, O, O, O, O,
-
-#define use_offset_0x16fe0u 8224
-
-
- /* Ideographic Symbols and Punctuation */
-
- /* 16FE0 */ O, O, O, O, B, O, O, O,
-
-#define use_offset_0x18b00u 8232
-
-
- /* Khitan Small Script */
-
- /* 18B00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18BF0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18C90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18CA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18CB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18CC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 18CD0 */ B, B, B, B, B, B, O, O,
-
-#define use_offset_0x1bc00u 8704
-
-
- /* Duployan */
-
- /* 1BC00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BC60 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O,
- /* 1BC70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
- /* 1BC80 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
- /* 1BC90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, CMBlw, CMBlw, O,
-
-#define use_offset_0x1e100u 8864
-
-
- /* Nyiakeng Puachue Hmong */
-
- /* 1E100 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E120 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
- /* 1E130 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, O, O,
- /* 1E140 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, B, B,
-
-#define use_offset_0x1e290u 8944
-
-
- /* Toto */
-
- /* 1E290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E2A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, O,
- /* 1E2B0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
-
- /* Wancho */
-
- /* 1E2C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E2D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E2E0 */ B, B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMAbv, VMAbv, VMAbv,
- /* 1E2F0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0x1e900u 9056
-
-
- /* Adlam */
-
- /* 1E900 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E930 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1E940 */ B, B, B, B, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, B, O, O, O, O,
- /* 1E950 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-
-#define use_offset_0xe0100u 9152
-
-
- /* Variation Selectors Supplement */
-
- /* E0100 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0110 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0120 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0130 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0140 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0150 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0160 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0170 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0180 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E0190 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E01A0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E01B0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E01C0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E01D0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
- /* E01E0 */ CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ, CGJ,
-
-}; /* Table items: 9392; occupancy: 79% */
-
-static inline uint8_t
-hb_use_get_category (hb_codepoint_t u)
-{
- switch (u >> 12)
- {
- case 0x0u:
- if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
- if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0348u, 0x034Fu)) return use_table[u - 0x0348u + use_offset_0x0348u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0640u, 0x0647u)) return use_table[u - 0x0640u + use_offset_0x0640u];
- if (hb_in_range<hb_codepoint_t> (u, 0x07C8u, 0x07FFu)) return use_table[u - 0x07C8u + use_offset_0x07c8u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0840u, 0x085Fu)) return use_table[u - 0x0840u + use_offset_0x0840u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
- if (hb_in_range<hb_codepoint_t> (u, 0x0F00u, 0x0FC7u)) return use_table[u - 0x0F00u + use_offset_0x0f00u];
- break;
-
- case 0x1u:
- if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1700u, 0x18AFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
- break;
-
- case 0x2u:
- if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
- if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return use_table[u - 0x2070u + use_offset_0x2070u];
- if (hb_in_range<hb_codepoint_t> (u, 0x20F0u, 0x20F7u)) return use_table[u - 0x20F0u + use_offset_0x20f0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x25C8u, 0x25CFu)) return use_table[u - 0x25C8u + use_offset_0x25c8u];
- if (hb_in_range<hb_codepoint_t> (u, 0x2D30u, 0x2D7Fu)) return use_table[u - 0x2D30u + use_offset_0x2d30u];
- break;
-
- case 0xAu:
- if (hb_in_range<hb_codepoint_t> (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
- if (hb_in_range<hb_codepoint_t> (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
- break;
-
- case 0xFu:
- if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
- break;
-
- case 0x10u:
- if (hb_in_range<hb_codepoint_t> (u, 0x10570u, 0x105BFu)) return use_table[u - 0x10570u + use_offset_0x10570u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10A00u, 0x10A4Fu)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return use_table[u - 0x10AC0u + use_offset_0x10ac0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return use_table[u - 0x10B80u + use_offset_0x10b80u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D3Fu)) return use_table[u - 0x10D00u + use_offset_0x10d00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10E80u, 0x10EB7u)) return use_table[u - 0x10E80u + use_offset_0x10e80u];
- if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x110C7u)) return use_table[u - 0x10F30u + use_offset_0x10f30u];
- break;
-
- case 0x11u:
- if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x110C7u)) return use_table[u - 0x10F30u + use_offset_0x10f30u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11580u, 0x11747u)) return use_table[u - 0x11580u + use_offset_0x11580u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11800u, 0x1183Fu)) return use_table[u - 0x11800u + use_offset_0x11800u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11900u, 0x1195Fu)) return use_table[u - 0x11900u + use_offset_0x11900u];
- if (hb_in_range<hb_codepoint_t> (u, 0x119A0u, 0x11A9Fu)) return use_table[u - 0x119A0u + use_offset_0x119a0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11D00u, 0x11DAFu)) return use_table[u - 0x11D00u + use_offset_0x11d00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x11EE0u, 0x11EF7u)) return use_table[u - 0x11EE0u + use_offset_0x11ee0u];
- break;
-
- case 0x13u:
- if (hb_in_range<hb_codepoint_t> (u, 0x13000u, 0x1343Fu)) return use_table[u - 0x13000u + use_offset_0x13000u];
- break;
-
- case 0x16u:
- if (hb_in_range<hb_codepoint_t> (u, 0x16AC0u, 0x16B37u)) return use_table[u - 0x16AC0u + use_offset_0x16ac0u];
- if (hb_in_range<hb_codepoint_t> (u, 0x16F00u, 0x16F97u)) return use_table[u - 0x16F00u + use_offset_0x16f00u];
- if (hb_in_range<hb_codepoint_t> (u, 0x16FE0u, 0x16FE7u)) return use_table[u - 0x16FE0u + use_offset_0x16fe0u];
- break;
-
- case 0x18u:
- if (hb_in_range<hb_codepoint_t> (u, 0x18B00u, 0x18CD7u)) return use_table[u - 0x18B00u + use_offset_0x18b00u];
- break;
-
- case 0x1Bu:
- if (hb_in_range<hb_codepoint_t> (u, 0x1BC00u, 0x1BC9Fu)) return use_table[u - 0x1BC00u + use_offset_0x1bc00u];
- break;
-
- case 0x1Eu:
- if (hb_in_range<hb_codepoint_t> (u, 0x1E100u, 0x1E14Fu)) return use_table[u - 0x1E100u + use_offset_0x1e100u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1E290u, 0x1E2FFu)) return use_table[u - 0x1E290u + use_offset_0x1e290u];
- if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E95Fu)) return use_table[u - 0x1E900u + use_offset_0x1e900u];
- break;
-
- case 0xE0u:
- if (hb_in_range<hb_codepoint_t> (u, 0xE0100u, 0xE01EFu)) return use_table[u - 0xE0100u + use_offset_0xe0100u];
- break;
-
- default:
- break;
- }
- return USE(O);
-}
-
-#undef B
-#undef CGJ
-#undef CS
-#undef G
-#undef GB
-#undef H
-#undef HN
-#undef HVM
-#undef J
-#undef N
-#undef O
-#undef R
-#undef SB
-#undef SE
-#undef SUB
-#undef Sk
-#undef ZWNJ
-#undef CMAbv
-#undef CMBlw
-#undef FAbv
-#undef FBlw
-#undef FPst
-#undef FMAbv
-#undef FMBlw
-#undef FMPst
-#undef MAbv
-#undef MBlw
-#undef MPst
-#undef MPre
-#undef SMAbv
-#undef SMBlw
-#undef VAbv
-#undef VBlw
-#undef VPst
-#undef VPre
-#undef VMAbv
-#undef VMBlw
-#undef VMPst
-#undef VMPre
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */
-/* == End of generated table == */
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index eb1bc7976..b2eedb027 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -446,6 +446,9 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
return;
#endif
+ if (!buffer->message (font, "start fallback mark"))
+ return;
+
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int start = 0;
@@ -457,6 +460,8 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
start = i;
}
position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing);
+
+ (void) buffer->message (font, "end fallback mark");
}
@@ -497,6 +502,9 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
!font->has_glyph_v_kerning_func ())
return;
+ if (!buffer->message (font, "start fallback kern"))
+ return;
+
bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
if (reverse)
@@ -508,6 +516,8 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
if (reverse)
buffer->reverse ();
+
+ (void) buffer->message (font, "end fallback kern");
#endif
}
@@ -525,6 +535,15 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED,
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
{
+ /* If font had no ASCII space and we used the invisible glyph, give it a 1/4 EM default advance. */
+ if (buffer->invisible && info[i].codepoint == buffer->invisible)
+ {
+ if (horizontal)
+ pos[i].x_advance = +font->x_scale / 4;
+ else
+ pos[i].y_advance = -font->y_scale / 4;
+ }
+
hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
hb_codepoint_t glyph;
typedef hb_unicode_funcs_t t;
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 839cc9122..897377aa1 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/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;
@@ -193,7 +192,8 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
{
hb_codepoint_t space_glyph;
hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
- if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph))
+ if (space_type != hb_unicode_funcs_t::NOT_SPACE &&
+ (c->font->get_nominal_glyph (0x0020, &space_glyph) || (space_glyph = buffer->invisible)))
{
_hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
next_char (buffer, space_glyph);
@@ -222,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;) {
@@ -341,7 +341,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
{
unsigned int end;
for (end = buffer->idx + 1; end < count; end++)
- if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end])))
+ if (_hb_glyph_info_is_unicode_mark (&buffer->info[end]))
break;
if (end < count)
@@ -374,7 +374,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
decompose_multi_char_cluster (&c, end, always_short_circuit);
}
while (buffer->idx < count && buffer->successful);
- buffer->swap_buffers ();
+ buffer->sync ();
}
@@ -394,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;
}
@@ -477,7 +477,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
if (info_cc (buffer->prev()) == 0)
starter = buffer->out_len - 1;
}
- buffer->swap_buffers ();
+ buffer->sync ();
}
}
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 4e8a4bc3d..bbdfc214a 100644
--- a/src/hb-ot-shape.cc
+++ b/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,14 +47,17 @@
#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
-_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props)
+_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t &props)
{
/* https://github.com/harfbuzz/harfbuzz/issues/2124 */
return hb_aat_layout_has_substitution (face) &&
- (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face));
+ (HB_DIRECTION_IS_HORIZONTAL (props.direction) || !hb_ot_layout_has_substitution (face));
}
#endif
@@ -74,23 +77,25 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
unsigned int num_user_features);
hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face,
- const hb_segment_properties_t *props) :
+ const hb_segment_properties_t &props) :
face (face),
- props (*props),
+ props (props),
map (face, props),
aat_map (face, props)
#ifndef HB_NO_AAT_SHAPE
, 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;
+#ifndef HB_NO_AAT_SHAPE
/* 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;
+#endif
}
void
@@ -222,7 +227,7 @@ hb_ot_shape_plan_t::init0 (hb_face_t *face,
#endif
hb_ot_shape_planner_t planner (face,
- &key->props);
+ key->props);
hb_ot_shape_collect_features (&planner,
key->user_features,
@@ -504,9 +509,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]);
}
@@ -524,18 +529,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
}
#endif
/* Or part of the Other_Grapheme_Extend that is not marks.
- * As of Unicode 11 that is just:
+ * As of Unicode 15 that is just:
*
* 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
* FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
* E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
*
* ZWNJ is special, we don't want to merge it as there's no need, and keeping
- * it separate results in more granular clusters. Ignore Katakana for now.
+ * it separate results in more granular clusters.
* Tags are used for Emoji sub-region flag sequences:
* https://github.com/harfbuzz/harfbuzz/issues/1556
+ * Katakana ones were requested:
+ * https://github.com/harfbuzz/harfbuzz/issues/3844
*/
- else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+ else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
_hb_glyph_info_set_continuation (&info[i]);
}
}
@@ -566,7 +573,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
info.mask = buffer->cur().mask;
(void) buffer->output_info (info);
- buffer->swap_buffers ();
+ buffer->sync ();
}
static void
@@ -598,24 +605,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;
}
@@ -628,20 +644,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
(HB_DIRECTION_IS_VERTICAL (direction) &&
direction != HB_DIRECTION_TTB))
{
-
- if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- foreach_grapheme (buffer, start, end)
- {
- buffer->merge_clusters (start, end);
- buffer->reverse_range (start, end);
- }
- else
- foreach_grapheme (buffer, start, end)
- /* form_clusters() merged clusters already, we don't merge. */
- buffer->reverse_range (start, end);
-
- buffer->reverse ();
-
+ _hb_ot_layout_reverse_graphemes (buffer);
buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
}
}
@@ -651,6 +654,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
* Substitute
*/
+#ifndef HB_NO_VERTICAL
static hb_codepoint_t
hb_vert_char_for (hb_codepoint_t u)
{
@@ -701,6 +705,7 @@ hb_vert_char_for (hb_codepoint_t u)
return u;
}
+#endif
static inline void
hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
@@ -723,6 +728,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
}
}
+#ifndef HB_NO_VERTICAL
if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
{
for (unsigned int i = 0; i < count; i++) {
@@ -731,6 +737,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
info[i].codepoint = codepoint;
}
}
+#endif
}
static inline void
@@ -859,7 +866,7 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
}
}
else
- hb_ot_layout_delete_glyphs_inplace (buffer, _hb_glyph_info_is_default_ignorable);
+ buffer->delete_glyphs_inplace (_hb_glyph_info_is_default_ignorable);
}
@@ -924,7 +931,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;
@@ -943,18 +950,24 @@ 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)
+ hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
}
static inline void
hb_ot_substitute_post (const hb_ot_shape_context_t *c)
{
- hb_ot_hide_default_ignorables (c->buffer, c->font);
#ifndef HB_NO_AAT_SHAPE
- if (c->plan->apply_morx)
+ if (c->plan->apply_morx && !c->plan->apply_gpos)
hb_aat_layout_remove_deleted_glyphs (c->buffer);
#endif
+ hb_ot_hide_default_ignorables (c->buffer, c->font);
+
if (c->plan->shaper->postprocess_glyphs &&
c->buffer->message(c->font, "start postprocess-glyphs")) {
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
@@ -1030,7 +1043,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;
@@ -1043,7 +1056,7 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c)
* hanging over the next glyph after the final reordering.
*
* Note: If fallback positinoing happens, we don't care about
- * this as it will be overriden.
+ * this as it will be overridden.
*/
bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing &&
HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
@@ -1115,7 +1128,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);
@@ -1129,23 +1142,42 @@ hb_propagate_flags (hb_buffer_t *buffer)
/* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
* Simplifies using them. */
- if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
+ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
return;
+ /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
+ *
+ * - If the places that the Arabic shaper marked as SAFE_TO_INSERT_TATWEEL,
+ * are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
+ * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
+ *
+ * We couldn't make this interaction earlier. It has to be done here.
+ */
+ bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+
+ bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
+
hb_glyph_info_t *info = buffer->info;
foreach_cluster (buffer, start, end)
{
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
- if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
- {
- mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
- break;
- }
- if (mask)
- for (unsigned int i = start; i < end; i++)
- info[i].mask |= mask;
+ mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
+
+ if (flip_tatweel)
+ {
+ if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+ mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
+ if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
+ mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+ }
+
+ if (clear_concat)
+ mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+
+ for (unsigned int i = start; i < end; i++)
+ info[i].mask = mask;
}
}
@@ -1154,19 +1186,6 @@ hb_propagate_flags (hb_buffer_t *buffer)
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
- c->buffer->deallocate_var_all ();
- c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
- if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
- {
- c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
- (unsigned) HB_BUFFER_MAX_LEN_MIN);
- }
- if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
- {
- c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
- (unsigned) HB_BUFFER_MAX_OPS_MIN);
- }
-
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
@@ -1197,9 +1216,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
c->buffer->props.direction = c->target_direction;
- c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
- c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
- c->buffer->deallocate_var_all ();
+ c->buffer->leave ();
}
diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh
index e8c81015c..ace28602f 100644
--- a/src/hb-ot-shape.hh
+++ b/src/hb-ot-shape.hh
@@ -51,7 +51,7 @@ struct hb_ot_shape_plan_key_t
bool equal (const hb_ot_shape_plan_key_t *other)
{
- return 0 == memcmp (this, other, sizeof (*this));
+ return 0 == hb_memcmp (this, other, sizeof (*this));
}
};
@@ -60,8 +60,10 @@ struct hb_shape_plan_key_t;
struct hb_ot_shape_plan_t
{
+ ~hb_ot_shape_plan_t () { fini (); }
+
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,10 +160,10 @@ 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);
+ const hb_segment_properties_t &props);
HB_INTERNAL void compile (hb_ot_shape_plan_t &plan,
const hb_ot_shape_plan_key_t &key);
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shaper-arabic-fallback.hh
index 78f46c1ca..b9f92f72d 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/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/src/hb-ot-shape-complex-arabic-joining-list.hh b/src/hb-ot-shaper-arabic-joining-list.hh
index e6339ee72..c7b57820a 100644
--- a/src/hb-ot-shape-complex-arabic-joining-list.hh
+++ b/src/hb-ot-shaper-arabic-joining-list.hh
@@ -6,14 +6,14 @@
*
* on files with these headers:
*
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 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/src/hb-ot-shaper-arabic-pua.hh b/src/hb-ot-shaper-arabic-pua.hh
new file mode 100644
index 000000000..ba86772f8
--- /dev/null
+++ b/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/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shaper-arabic-table.hh
index c158964f2..d7670f2f9 100644
--- a/src/hb-ot-shape-complex-arabic-table.hh
+++ b/src/hb-ot-shaper-arabic-table.hh
@@ -6,15 +6,15 @@
*
* on files with these headers:
*
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58:00 GMT [KW]
* 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/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shaper-arabic-win1256.hh
index 41e3dd38a..b8d481c81 100644
--- a/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/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
/*
@@ -87,6 +87,8 @@
#define OT_GLYPHID /* GlyphID */ \
OT_UINT16
+/* Shorthand. */
+#define G OT_GLYPHID
#define OT_UARRAY(Name, Items) \
OT_LABEL_START(Name) \
@@ -183,8 +185,6 @@
Tag \
OT_OFFSET(manifest, Name)
-/* Shorthand. */
-#define G OT_GLYPHID
/*
* Table Start
@@ -300,14 +300,40 @@ OT_TABLE_END
/*
* Clean up
*/
+
+#undef MANIFEST
+#undef MANIFEST_LOOKUP
+
#undef OT_TABLE_START
#undef OT_TABLE_END
#undef OT_LABEL_START
#undef OT_LABEL_END
#undef OT_UINT8
#undef OT_UINT16
-#undef OT_DISTANCE
#undef OT_COUNT
+#undef OT_DISTANCE
+
+#undef OT_LABEL
+#undef OT_LIST
+
+#undef OT_TAG
+#undef OT_OFFSET
+#undef OT_GLYPHID
+#undef G
+#undef OT_UARRAY
+#undef OT_UHEADLESSARRAY
+
+#undef OT_LOOKUP_FLAG_IGNORE_MARKS
+#undef OT_LOOKUP
+#undef OT_SUBLOOKUP
+#undef OT_COVERAGE1
+#undef OT_LOOKUP_TYPE_SUBST_SINGLE
+#undef OT_LOOKUP_TYPE_SUBST_LIGATURE
+#undef OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2
+#undef OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1
+#undef OT_LIGATURE_SET
+#undef OT_LIGATURE
+
/*
* Include a second time to get the table data...
@@ -316,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/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shaper-arabic.cc
index 222c5d6b7..2332ae369 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/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)
{
@@ -161,16 +161,25 @@ static const struct arabic_state_table_entry {
};
-static void
+static bool
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
+static bool
+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);
+ return false;
+}
+
static void
collect_features_arabic (hb_ot_shape_planner_t *plan)
{
@@ -193,26 +202,24 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* work. However, testing shows that rlig and calt are applied
* together for Mongolian in Uniscribe. As such, we only add a
* pause for Arabic, not other scripts.
- *
- * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
- * work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505
*/
map->enable_feature (HB_TAG('s','t','c','h'));
map->add_gsub_pause (record_stch);
- map->enable_feature (HB_TAG('c','c','m','p'));
- map->enable_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('c','c','m','p'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('l','o','c','l'), F_MANUAL_ZWJ);
map->add_gsub_pause (nullptr);
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
{
bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
- map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE);
+ map->add_feature (arabic_features[i], F_MANUAL_ZWJ | (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
@@ -223,10 +230,16 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
if (plan->props.script == HB_SCRIPT_ARABIC)
map->add_gsub_pause (arabic_fallback_shape);
- /* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */
- map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
- map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
- map->add_gsub_pause (nullptr);
+ map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
+ /* https://github.com/harfbuzz/harfbuzz/issues/1573 */
+ if (!map->has_feature (HB_TAG('r','c','l','t')))
+ {
+ map->add_gsub_pause (nullptr);
+ map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
+ }
+
+ map->enable_feature (HB_TAG('l','i','g','a'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('c','l','i','g'), F_MANUAL_ZWJ);
/* The spec includes 'cswh'. Earlier versions of Windows
* used to enable this by default, but testing suggests
@@ -236,11 +249,11 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
- //map->enable_feature (HB_TAG('c','s','w','h'));
- map->enable_feature (HB_TAG('m','s','e','t'));
+ //map->enable_feature (HB_TAG('c','s','w','h'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('m','s','e','t'), F_MANUAL_ZWJ);
}
-#include "hb-ot-shape-complex-arabic-fallback.hh"
+#include "hb-ot-shaper-arabic-fallback.hh"
struct arabic_shape_plan_t
{
@@ -319,7 +332,21 @@ arabic_joining (hb_buffer_t *buffer)
if (entry->prev_action != NONE && prev != UINT_MAX)
{
info[prev].arabic_shaping_action() = entry->prev_action;
- buffer->unsafe_to_break (prev, i + 1);
+ buffer->safe_to_insert_tatweel (prev, i + 1);
+ }
+ else
+ {
+ if (prev == UINT_MAX)
+ {
+ if (this_type >= JOINING_TYPE_R)
+ buffer->unsafe_to_concat_from_outbuffer (0, i + 1);
+ }
+ else
+ {
+ if (this_type >= JOINING_TYPE_R ||
+ (2 <= state && state <= 5) /* States that have a possible prev_action. */)
+ buffer->unsafe_to_concat (prev, i + 1);
+ }
}
info[i].arabic_shaping_action() = entry->curr_action;
@@ -337,7 +364,14 @@ arabic_joining (hb_buffer_t *buffer)
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != UINT_MAX)
+ {
info[prev].arabic_shaping_action() = entry->prev_action;
+ buffer->safe_to_insert_tatweel (prev, buffer->len);
+ }
+ else if (2 <= state && state <= 5) /* States that have a possible prev_action. */
+ {
+ buffer->unsafe_to_concat (prev, buffer->len);
+ }
break;
}
}
@@ -379,19 +413,19 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
}
-static void
+static bool
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
- return;
+#ifdef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+ return false;
#endif
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->do_fallback)
- return;
+ return false;
retry:
arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan;
@@ -407,6 +441,7 @@ retry:
}
arabic_fallback_plan_shape (fallback_plan, font, buffer);
+ return true;
}
/*
@@ -417,14 +452,14 @@ retry:
* marks can use it as well.
*/
-static void
+static bool
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->has_stch)
- return;
+ return false;
/* 'stch' feature was just applied. Look for anything that multiplied,
* and record it for stch treatment later. Note that rtlm, frac, etc
@@ -440,6 +475,7 @@ record_stch (const hb_ot_shape_plan_t *plan,
info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
}
+ return false;
}
static void
@@ -598,8 +634,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/ */
@@ -614,6 +648,11 @@ modifier_combining_marks[] =
0x06E3u, /* ARABIC SMALL LOW SEEN */
0x06E7u, /* ARABIC SMALL HIGH YEH */
0x06E8u, /* ARABIC SMALL HIGH NOON */
+ 0x08CAu, /* ARABIC SMALL HIGH FARSI YEH */
+ 0x08CBu, /* ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW */
+ 0x08CDu, /* ARABIC SMALL HIGH ZAH */
+ 0x08CEu, /* ARABIC LARGE ROUND DOT ABOVE */
+ 0x08CFu, /* ARABIC LARGE ROUND DOT BELOW */
0x08D3u, /* ARABIC SMALL LOW WAW */
0x08F3u, /* ARABIC SMALL HIGH WAW */
};
@@ -663,7 +702,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));
@@ -694,7 +733,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 */
@@ -702,12 +741,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
data_destroy_arabic,
nullptr, /* preprocess_text */
postprocess_glyphs_arabic,
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
nullptr, /* decompose */
nullptr, /* compose */
setup_masks_arabic,
- HB_TAG_NONE, /* gpos_tag */
reorder_marks_arabic,
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-arabic.hh b/src/hb-ot-shaper-arabic.hh
index 5bf6ff633..a025b1a39 100644
--- a/src/hb-ot-shape-complex-arabic.hh
+++ b/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/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shaper-default.cc
index a755aea09..f0404a4d2 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/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 */
@@ -39,19 +39,20 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
+#ifndef HB_NO_AAT_SHAPE
/* 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 */
@@ -59,15 +60,16 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber =
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
+#endif
#endif
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shaper-hangul.cc
index 0d84a76b8..c90476bc4 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/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,
@@ -140,7 +140,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
*
* - LV can be precomposed, or decomposed. Lets call those
* <LV> and <L,V>,
- * - LVT can be fully precomposed, partically precomposed, or
+ * - LVT can be fully precomposed, partially precomposed, or
* fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>.
*
* The composition / decomposition is mechanical. However, not
@@ -392,7 +392,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
*/
(void) buffer->next_glyph ();
}
- buffer->swap_buffers ();
+ buffer->sync ();
}
static void
@@ -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,
@@ -422,12 +422,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
data_destroy_hangul,
preprocess_text_hangul,
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
nullptr, /* decompose */
nullptr, /* compose */
setup_masks_hangul,
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shaper-hebrew.cc
index 334d3ded8..e18edd6b3 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/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
@@ -89,7 +89,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
found = true;
}
break;
- case 0x05B7u: /* patah */
+ case 0x05B7u: /* PATAH */
if (a == 0x05F2u) { /* YIDDISH YOD YOD */
*ab = 0xFB1Fu;
found = true;
@@ -162,8 +162,34 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
return found;
}
+static void
+reorder_marks_hebrew (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end)
+{
+ hb_glyph_info_t *info = buffer->info;
+
+ for (unsigned i = start + 2; i < end; i++)
+ {
+ unsigned c0 = info_cc (info[i - 2]);
+ unsigned c1 = info_cc (info[i - 1]);
+ unsigned c2 = info_cc (info[i - 0]);
+
+ if ((c0 == HB_MODIFIED_COMBINING_CLASS_CCC17 || c0 == HB_MODIFIED_COMBINING_CLASS_CCC18) /* patach or qamats */ &&
+ (c1 == HB_MODIFIED_COMBINING_CLASS_CCC10 || c1 == HB_MODIFIED_COMBINING_CLASS_CCC14) /* sheva or hiriq */ &&
+ (c2 == HB_MODIFIED_COMBINING_CLASS_CCC22 || c2 == HB_UNICODE_COMBINING_CLASS_BELOW) /* meteg or below */)
+ {
+ buffer->merge_clusters (i - 1, i + 1);
+ hb_swap (info[i - 1], info[i]);
+ break;
+ }
+ }
-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 */
@@ -171,12 +197,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
nullptr, /* decompose */
compose_hebrew,
nullptr, /* setup_masks */
+ reorder_marks_hebrew,
HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */
- nullptr, /* reorder_marks */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shaper-indic-machine.hh b/src/hb-ot-shaper-indic-machine.hh
new file mode 100644
index 000000000..d6c67b81b
--- /dev/null
+++ b/src/hb-ot-shaper-indic-machine.hh
@@ -0,0 +1,627 @@
+
+#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 54 "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_MPst 13u
+#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 75 "hb-ot-shaper-indic-machine.hh"
+static const unsigned char _indic_syllable_machine_trans_keys[] = {
+ 8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
+ 8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
+ 8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u,
+ 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 5u, 13u, 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, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u,
+ 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, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 13u, 3u, 16u, 3u, 16u,
+ 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u,
+ 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 13u, 4u, 13u, 3u, 16u, 3u, 16u,
+ 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u,
+ 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u,
+ 5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 13u, 5u, 13u,
+ 5u, 13u, 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, 10, 9, 9, 1, 10, 10, 10,
+ 1, 9, 9, 1, 10, 10, 10, 10,
+ 1, 9, 9, 1, 10, 10, 10, 1,
+ 9, 9, 1, 10, 10, 9, 1, 18,
+ 14, 14, 13, 15, 5, 5, 1, 5,
+ 15, 15, 15, 11, 10, 9, 9, 10,
+ 5, 7, 5, 14, 14, 14, 14, 13,
+ 15, 14, 14, 13, 15, 5, 1, 5,
+ 15, 15, 11, 10, 9, 9, 10, 5,
+ 5, 7, 5, 14, 14, 10, 14, 14,
+ 13, 15, 14, 15, 5, 1, 5, 15,
+ 15, 11, 10, 9, 9, 14, 10, 5,
+ 5, 7, 5, 14, 10, 10, 14, 14,
+ 13, 15, 14, 15, 5, 1, 5, 15,
+ 15, 11, 10, 9, 9, 14, 10, 5,
+ 5, 7, 5, 16, 14, 16, 10, 9,
+ 9, 1, 5, 15, 7, 5, 5, 1,
+ 5, 15
+};
+
+static const short _indic_syllable_machine_index_offsets[] = {
+ 0, 2, 13, 23, 33, 35, 46, 57,
+ 68, 70, 80, 90, 92, 103, 114, 125,
+ 136, 138, 148, 158, 160, 171, 182, 193,
+ 195, 205, 215, 217, 228, 239, 249, 251,
+ 270, 285, 300, 314, 330, 336, 342, 344,
+ 350, 366, 382, 398, 410, 421, 431, 441,
+ 452, 458, 466, 472, 487, 502, 517, 532,
+ 546, 562, 577, 592, 606, 622, 628, 630,
+ 636, 652, 668, 680, 691, 701, 711, 722,
+ 728, 734, 742, 748, 763, 778, 789, 804,
+ 819, 833, 849, 864, 880, 886, 888, 894,
+ 910, 926, 938, 949, 959, 969, 984, 995,
+ 1001, 1007, 1015, 1021, 1036, 1047, 1058, 1073,
+ 1088, 1102, 1118, 1133, 1149, 1155, 1157, 1163,
+ 1179, 1195, 1207, 1218, 1228, 1238, 1253, 1264,
+ 1270, 1276, 1284, 1290, 1307, 1322, 1339, 1350,
+ 1360, 1370, 1372, 1378, 1394, 1402, 1408, 1414,
+ 1416, 1422
+};
+
+static const unsigned char _indic_syllable_machine_indicies[] = {
+ 1, 0, 2, 3, 3, 4, 5, 0,
+ 0, 0, 0, 4, 0, 3, 3, 4,
+ 6, 0, 0, 0, 0, 4, 0, 3,
+ 3, 4, 5, 0, 0, 0, 0, 4,
+ 0, 4, 0, 7, 3, 3, 4, 5,
+ 0, 0, 0, 0, 4, 0, 2, 3,
+ 3, 4, 5, 0, 0, 0, 8, 4,
+ 0, 10, 11, 11, 12, 13, 9, 9,
+ 9, 9, 12, 9, 14, 9, 11, 11,
+ 12, 15, 9, 9, 9, 9, 12, 9,
+ 11, 11, 12, 13, 9, 9, 9, 9,
+ 12, 9, 12, 9, 16, 11, 11, 12,
+ 13, 9, 9, 9, 9, 12, 9, 10,
+ 11, 11, 12, 13, 9, 9, 9, 17,
+ 12, 9, 10, 11, 11, 12, 13, 9,
+ 9, 9, 18, 12, 9, 20, 21, 21,
+ 22, 23, 19, 19, 19, 24, 22, 19,
+ 25, 19, 21, 21, 22, 27, 26, 26,
+ 26, 26, 22, 26, 21, 21, 22, 23,
+ 19, 19, 19, 19, 22, 19, 22, 26,
+ 20, 21, 21, 22, 23, 19, 19, 19,
+ 19, 22, 19, 28, 21, 21, 22, 23,
+ 19, 19, 19, 19, 22, 19, 30, 31,
+ 31, 32, 33, 29, 29, 29, 34, 32,
+ 29, 35, 29, 31, 31, 32, 36, 29,
+ 29, 29, 29, 32, 29, 31, 31, 32,
+ 33, 29, 29, 29, 29, 32, 29, 32,
+ 29, 30, 31, 31, 32, 33, 29, 29,
+ 29, 29, 32, 29, 37, 31, 31, 32,
+ 33, 29, 29, 29, 29, 32, 29, 21,
+ 21, 22, 38, 0, 0, 0, 0, 22,
+ 0, 40, 39, 42, 43, 44, 45, 46,
+ 47, 22, 23, 48, 49, 49, 24, 22,
+ 50, 51, 52, 53, 54, 41, 56, 57,
+ 58, 59, 4, 5, 60, 55, 55, 8,
+ 4, 55, 55, 61, 55, 62, 57, 63,
+ 63, 4, 5, 60, 55, 55, 55, 4,
+ 55, 55, 61, 55, 57, 63, 63, 4,
+ 5, 60, 55, 55, 55, 4, 55, 55,
+ 61, 55, 42, 55, 55, 55, 64, 65,
+ 55, 1, 60, 55, 55, 55, 55, 55,
+ 42, 55, 66, 66, 55, 1, 60, 55,
+ 60, 55, 55, 67, 60, 55, 60, 55,
+ 60, 55, 55, 55, 60, 55, 42, 55,
+ 68, 55, 66, 66, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 42, 55,
+ 55, 55, 66, 66, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 42, 55,
+ 55, 55, 66, 65, 55, 1, 60, 55,
+ 55, 55, 55, 55, 42, 55, 69, 70,
+ 71, 71, 4, 5, 60, 55, 55, 55,
+ 4, 55, 70, 71, 71, 4, 5, 60,
+ 55, 55, 55, 4, 55, 71, 71, 4,
+ 5, 60, 55, 55, 55, 4, 55, 60,
+ 55, 55, 67, 60, 55, 55, 55, 4,
+ 55, 72, 73, 73, 4, 5, 60, 55,
+ 55, 55, 4, 55, 64, 74, 55, 1,
+ 60, 55, 64, 55, 66, 66, 55, 1,
+ 60, 55, 66, 74, 55, 1, 60, 55,
+ 56, 57, 63, 63, 4, 5, 60, 55,
+ 55, 55, 4, 55, 55, 61, 55, 56,
+ 57, 58, 63, 4, 5, 60, 55, 55,
+ 8, 4, 55, 55, 61, 55, 76, 77,
+ 78, 79, 12, 13, 80, 75, 75, 18,
+ 12, 75, 75, 81, 75, 82, 77, 83,
+ 79, 12, 13, 80, 75, 75, 75, 12,
+ 75, 75, 81, 75, 77, 83, 79, 12,
+ 13, 80, 75, 75, 75, 12, 75, 75,
+ 81, 75, 84, 75, 75, 75, 85, 86,
+ 75, 14, 80, 75, 75, 75, 75, 75,
+ 84, 75, 87, 77, 88, 89, 12, 13,
+ 80, 75, 75, 17, 12, 75, 75, 81,
+ 75, 90, 77, 83, 83, 12, 13, 80,
+ 75, 75, 75, 12, 75, 75, 81, 75,
+ 77, 83, 83, 12, 13, 80, 75, 75,
+ 75, 12, 75, 75, 81, 75, 84, 75,
+ 75, 75, 91, 86, 75, 14, 80, 75,
+ 75, 75, 75, 75, 84, 75, 80, 75,
+ 75, 92, 80, 75, 80, 75, 80, 75,
+ 75, 75, 80, 75, 84, 75, 93, 75,
+ 91, 91, 75, 14, 80, 75, 75, 75,
+ 75, 75, 84, 75, 84, 75, 75, 75,
+ 91, 91, 75, 14, 80, 75, 75, 75,
+ 75, 75, 84, 75, 94, 95, 96, 96,
+ 12, 13, 80, 75, 75, 75, 12, 75,
+ 95, 96, 96, 12, 13, 80, 75, 75,
+ 75, 12, 75, 96, 96, 12, 13, 80,
+ 75, 75, 75, 12, 75, 80, 75, 75,
+ 92, 80, 75, 75, 75, 12, 75, 97,
+ 98, 98, 12, 13, 80, 75, 75, 75,
+ 12, 75, 85, 99, 75, 14, 80, 75,
+ 91, 91, 75, 14, 80, 75, 85, 75,
+ 91, 91, 75, 14, 80, 75, 91, 99,
+ 75, 14, 80, 75, 87, 77, 83, 83,
+ 12, 13, 80, 75, 75, 75, 12, 75,
+ 75, 81, 75, 87, 77, 88, 83, 12,
+ 13, 80, 75, 75, 17, 12, 75, 75,
+ 81, 75, 10, 11, 11, 12, 13, 75,
+ 75, 75, 75, 12, 75, 76, 77, 83,
+ 79, 12, 13, 80, 75, 75, 75, 12,
+ 75, 75, 81, 75, 101, 45, 102, 102,
+ 22, 23, 48, 100, 100, 100, 22, 100,
+ 100, 52, 100, 45, 102, 102, 22, 23,
+ 48, 100, 100, 100, 22, 100, 100, 52,
+ 100, 103, 100, 100, 100, 104, 105, 100,
+ 25, 48, 100, 100, 100, 100, 100, 103,
+ 100, 44, 45, 106, 107, 22, 23, 48,
+ 100, 100, 24, 22, 100, 100, 52, 100,
+ 103, 100, 100, 100, 108, 105, 100, 25,
+ 48, 100, 100, 100, 100, 100, 103, 100,
+ 48, 100, 100, 109, 48, 100, 48, 100,
+ 48, 100, 100, 100, 48, 100, 103, 100,
+ 110, 100, 108, 108, 100, 25, 48, 100,
+ 100, 100, 100, 100, 103, 100, 103, 100,
+ 100, 100, 108, 108, 100, 25, 48, 100,
+ 100, 100, 100, 100, 103, 100, 111, 112,
+ 113, 113, 22, 23, 48, 100, 100, 100,
+ 22, 100, 112, 113, 113, 22, 23, 48,
+ 100, 100, 100, 22, 100, 113, 113, 22,
+ 23, 48, 100, 100, 100, 22, 100, 48,
+ 100, 100, 109, 48, 100, 100, 100, 22,
+ 100, 44, 45, 102, 102, 22, 23, 48,
+ 100, 100, 100, 22, 100, 100, 52, 100,
+ 114, 115, 115, 22, 23, 48, 100, 100,
+ 100, 22, 100, 104, 116, 100, 25, 48,
+ 100, 108, 108, 100, 25, 48, 100, 104,
+ 100, 108, 108, 100, 25, 48, 100, 108,
+ 116, 100, 25, 48, 100, 44, 45, 106,
+ 102, 22, 23, 48, 100, 100, 24, 22,
+ 100, 100, 52, 100, 20, 21, 21, 22,
+ 23, 117, 117, 117, 24, 22, 117, 20,
+ 21, 21, 22, 23, 117, 117, 117, 117,
+ 22, 117, 119, 120, 121, 122, 32, 33,
+ 123, 118, 118, 34, 32, 118, 118, 124,
+ 118, 125, 120, 122, 122, 32, 33, 123,
+ 118, 118, 118, 32, 118, 118, 124, 118,
+ 120, 122, 122, 32, 33, 123, 118, 118,
+ 118, 32, 118, 118, 124, 118, 126, 118,
+ 118, 118, 127, 128, 118, 35, 123, 118,
+ 118, 118, 118, 118, 126, 118, 119, 120,
+ 121, 49, 32, 33, 123, 118, 118, 34,
+ 32, 118, 118, 124, 118, 126, 118, 118,
+ 118, 129, 128, 118, 35, 123, 118, 118,
+ 118, 118, 118, 126, 118, 123, 118, 118,
+ 130, 123, 118, 123, 118, 123, 118, 118,
+ 118, 123, 118, 126, 118, 131, 118, 129,
+ 129, 118, 35, 123, 118, 118, 118, 118,
+ 118, 126, 118, 126, 118, 118, 118, 129,
+ 129, 118, 35, 123, 118, 118, 118, 118,
+ 118, 126, 118, 132, 133, 134, 134, 32,
+ 33, 123, 118, 118, 118, 32, 118, 133,
+ 134, 134, 32, 33, 123, 118, 118, 118,
+ 32, 118, 134, 134, 32, 33, 123, 118,
+ 118, 118, 32, 118, 123, 118, 118, 130,
+ 123, 118, 118, 118, 32, 118, 119, 120,
+ 122, 122, 32, 33, 123, 118, 118, 118,
+ 32, 118, 118, 124, 118, 135, 136, 136,
+ 32, 33, 123, 118, 118, 118, 32, 118,
+ 127, 137, 118, 35, 123, 118, 129, 129,
+ 118, 35, 123, 118, 127, 118, 129, 129,
+ 118, 35, 123, 118, 129, 137, 118, 35,
+ 123, 118, 42, 43, 44, 45, 106, 102,
+ 22, 23, 48, 49, 49, 24, 22, 100,
+ 42, 52, 100, 56, 138, 58, 59, 4,
+ 5, 60, 55, 55, 8, 4, 55, 55,
+ 61, 55, 42, 43, 44, 45, 139, 140,
+ 22, 141, 142, 55, 49, 24, 22, 55,
+ 42, 52, 55, 20, 143, 143, 22, 141,
+ 60, 55, 55, 24, 22, 55, 60, 55,
+ 55, 67, 60, 55, 55, 55, 22, 55,
+ 142, 55, 55, 144, 142, 55, 55, 55,
+ 22, 55, 142, 55, 142, 55, 55, 55,
+ 142, 55, 42, 55, 68, 20, 143, 143,
+ 22, 141, 60, 55, 55, 55, 22, 55,
+ 42, 55, 146, 145, 147, 147, 145, 40,
+ 148, 145, 147, 147, 145, 40, 148, 145,
+ 148, 145, 145, 149, 148, 145, 148, 145,
+ 148, 145, 145, 145, 148, 145, 42, 117,
+ 117, 117, 117, 117, 117, 117, 117, 49,
+ 117, 117, 117, 117, 42, 117, 0
+};
+
+static const unsigned char _indic_syllable_machine_trans_targs[] = {
+ 31, 37, 42, 2, 43, 46, 4, 50,
+ 51, 31, 60, 9, 66, 69, 61, 11,
+ 74, 75, 78, 31, 83, 17, 89, 92,
+ 93, 84, 31, 19, 98, 31, 107, 24,
+ 113, 116, 117, 108, 26, 122, 127, 31,
+ 134, 31, 32, 53, 79, 81, 100, 101,
+ 85, 102, 123, 124, 94, 132, 137, 31,
+ 33, 35, 6, 52, 38, 47, 34, 1,
+ 36, 40, 0, 39, 41, 44, 45, 3,
+ 48, 5, 49, 31, 54, 56, 14, 77,
+ 62, 70, 55, 7, 57, 72, 64, 58,
+ 13, 76, 59, 8, 63, 65, 67, 68,
+ 10, 71, 12, 73, 31, 80, 20, 82,
+ 96, 87, 15, 99, 16, 86, 88, 90,
+ 91, 18, 95, 21, 97, 31, 31, 103,
+ 105, 22, 27, 109, 118, 104, 106, 120,
+ 111, 23, 110, 112, 114, 115, 25, 119,
+ 28, 121, 125, 126, 131, 128, 129, 29,
+ 130, 31, 133, 30, 135, 136
+};
+
+static const char _indic_syllable_machine_trans_actions[] = {
+ 1, 0, 2, 0, 2, 0, 0, 2,
+ 2, 3, 2, 0, 2, 0, 0, 0,
+ 2, 2, 2, 4, 2, 0, 5, 0,
+ 5, 0, 6, 0, 2, 7, 2, 0,
+ 2, 0, 2, 0, 0, 2, 0, 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, 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, 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, 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, 0, 0, 0,
+ 0, 0
+};
+
+static const short _indic_syllable_machine_eof_trans[] = {
+ 1, 1, 1, 1, 1, 1, 1, 10,
+ 10, 10, 10, 10, 10, 10, 10, 20,
+ 20, 27, 20, 27, 20, 20, 30, 30,
+ 30, 30, 30, 30, 30, 1, 40, 0,
+ 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 118, 118, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 101, 56, 56, 56, 56,
+ 56, 56, 56, 56, 146, 146, 146, 146,
+ 146, 118
+};
+
+static const int indic_syllable_machine_start = 31;
+static const int indic_syllable_machine_first_final = 31;
+static const int indic_syllable_machine_error = -1;
+
+static const int indic_syllable_machine_en_main = 31;
+
+
+#line 58 "hb-ot-shaper-indic-machine.rl"
+
+
+
+#line 118 "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 (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 453 "hb-ot-shaper-indic-machine.hh"
+ {
+ cs = indic_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 138 "hb-ot-shaper-indic-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 465 "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 477 "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 114 "hb-ot-shaper-indic-machine.rl"
+ {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
+ break;
+ case 13:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
+ break;
+ case 14:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
+ break;
+ case 17:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
+ break;
+ case 19:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
+ break;
+ case 15:
+#line 113 "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 114 "hb-ot-shaper-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
+ break;
+ case 1:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
+ break;
+ case 3:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
+ break;
+ case 7:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
+ break;
+ case 8:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
+ break;
+ case 4:
+#line 113 "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 109 "hb-ot-shaper-indic-machine.rl"
+ {act = 1;}
+ break;
+ case 5:
+#line 1 "NONE"
+ {te = p+1;}
+#line 113 "hb-ot-shaper-indic-machine.rl"
+ {act = 5;}
+ break;
+ case 12:
+#line 1 "NONE"
+ {te = p+1;}
+#line 114 "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 566 "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 146 "hb-ot-shaper-indic-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shaper-indic-machine.rl
index df9583f32..46841884d 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shaper-indic-machine.rl
@@ -24,11 +24,23 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
+#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,
@@ -47,6 +59,8 @@ enum indic_syllable_type_t {
%%{
+
+export X = 0;
export C = 1;
export V = 2;
export N = 3;
@@ -55,15 +69,18 @@ export ZWNJ = 5;
export ZWJ = 6;
export M = 7;
export SM = 8;
-export A = 10;
-export PLACEHOLDER = 11;
-export DOTTEDCIRCLE = 12;
-export RS = 13;
-export Repha = 15;
-export Ra = 16;
-export CM = 17;
-export Symbol= 18;
-export CS = 19;
+export A = 9;
+export VD = 9;
+export PLACEHOLDER = 10;
+export DOTTEDCIRCLE = 11;
+export RS = 12;
+export MPst = 13;
+export Repha = 14;
+export Ra = 15;
+export CM = 16;
+export Symbol= 17;
+export CS = 18;
+
c = (C | Ra); # is_consonant
n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier
@@ -71,10 +88,9 @@ z = ZWJ|ZWNJ; # is_joiner
reph = (Ra H | Repha); # possible reph
cn = c.ZWJ?.n?;
-forced_rakar = ZWJ H ZWJ Ra;
symbol = Symbol.N?;
-matra_group = z*.M.N?.(H | forced_rakar)?;
-syllable_tail = (z?.SM.SM?.ZWNJ?)? A*;
+matra_group = z*.(M | SM? MPst).N?.H?;
+syllable_tail = (z?.SM.SM?.ZWNJ?)? (A | VD)*;
halant_group = (z?.H.(ZWJ.N?)?);
final_halant_group = halant_group | H.ZWNJ;
medial_group = CM?;
@@ -94,7 +110,7 @@ main := |*
vowel_syllable => { found_syllable (indic_vowel_syllable); };
standalone_cluster => { found_syllable (indic_standalone_cluster); };
symbol_cluster => { found_syllable (indic_symbol_cluster); };
- broken_cluster => { found_syllable (indic_broken_cluster); };
+ broken_cluster => { found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
other => { found_syllable (indic_non_indic_cluster); };
*|;
@@ -107,10 +123,10 @@ main := |*
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; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
-static void
+inline void
find_syllables_indic (hb_buffer_t *buffer)
{
unsigned int p, pe, eof, ts, te, act;
@@ -132,4 +148,4 @@ find_syllables_indic (hb_buffer_t *buffer)
#undef found_syllable
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
+#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shaper-indic-table.cc b/src/hb-ot-shaper-indic-table.cc
new file mode 100644
index 000000000..d9fb0510e
--- /dev/null
+++ b/src/hb-ot-shaper-indic-table.cc
@@ -0,0 +1,561 @@
+/* == 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-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # IndicPositionalCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58: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_MPst I_Cat(MPst)
+#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 /* 142 chars; M */
+#define _OT_MH OT_MH /* 1 chars; MH */
+#define _OT_ML OT_ML /* 1 chars; ML */
+#define _OT_MP OT_MPst /* 1 chars; MPst */
+#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 /* 56 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 /* 130 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 */_(MP,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),_(SM,SM), _(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),
+
+#define indic_offset_0x11338u 1720
+
+ /* 11338 */ _(X,X), _(X,X), _(X,X), _(N,X), _(N,X), _(X,X), _(X,X), _(X,X),
+
+}; /* Table items: 1728; occupancy: 71% */
+
+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, 0x11307u)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x11338u, 0x1133Fu)) return indic_table[u - 0x11338u + indic_offset_0x11338u];
+ 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_MP
+#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/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shaper-indic.cc
index 4a8781c8f..7652210d9 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/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,79 @@
*/
+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_;
+ lookups = map->get_stage_lookups (0/*GSUB*/,
+ map->get_feature_stage (0/*GSUB*/, feature_tag));
+ }
+
+ bool would_substitute (const hb_codepoint_t *glyphs,
+ unsigned int glyphs_count,
+ hb_face_t *face) const
+ {
+ for (const auto &lookup : lookups)
+ if (hb_ot_layout_lookup_would_substitute (face, lookup.index, glyphs, glyphs_count, zero_context))
+ return true;
+ return false;
+ }
+
+ private:
+ hb_array_t<const hb_ot_map_t::lookup_map_t> lookups;
+ 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 +120,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 +141,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 +149,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[] =
{
@@ -109,17 +170,17 @@ indic_features[] =
* These features are applied in order, one at a time, after initial_reordering,
* constrained to the syllable.
*/
- {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS},
- {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
- {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
- {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
- {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS},
- {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
- {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once, after final_reordering, constrained
@@ -127,12 +188,12 @@ indic_features[] =
* Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features.
*/
- {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS},
- {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
- {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
};
/*
@@ -162,15 +223,15 @@ enum {
INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */
};
-static void
+static bool
setup_syllables_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
final_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -183,10 +244,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_indic);
- map->enable_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
- map->enable_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
@@ -201,14 +262,13 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
for (; i < INDIC_NUM_FEATURES; i++)
map->add_feature (indic_features[i]);
-
- map->add_gsub_pause (_hb_clear_syllables);
}
static void
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
}
@@ -216,7 +276,7 @@ struct indic_shape_plan_t
{
bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
{
- hb_codepoint_t glyph = virama_glyph.get_relaxed ();
+ hb_codepoint_t glyph = virama_glyph;
if (unlikely (glyph == (hb_codepoint_t) -1))
{
if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
@@ -226,7 +286,7 @@ struct indic_shape_plan_t
/* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
* during shape planning... Instead, overwrite it here. */
- virama_glyph.set_relaxed ((int) glyph);
+ virama_glyph = (int) glyph;
}
*pglyph = glyph;
@@ -270,7 +330,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
#endif
- indic_plan->virama_glyph.set_relaxed (-1);
+ indic_plan->virama_glyph = -1;
/* Use zero-context would_substitute() matching for new-spec of the main
* Indic scripts, and scripts with one spec only, but not for old-specs.
@@ -353,14 +413,16 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_indic_properties (info[i]);
}
-static void
+static bool
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);
+ return false;
}
static int
@@ -369,7 +431,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;
}
@@ -381,9 +443,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))
{
@@ -418,9 +477,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];
@@ -454,7 +513,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. */
@@ -472,7 +531,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]))
@@ -481,84 +540,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 (info[i].indic_position() == POS_BELOW_C)
+ seen_below = true;
- if (!has_reph)
- base = limit;
-
- /* 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)
@@ -613,18 +639,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;
@@ -661,14 +675,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]));
@@ -683,20 +697,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) {
@@ -705,6 +715,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
}
}
} else if (info[i].indic_position() != POS_SMVD) {
+ if (info[i].indic_category() == I_Cat(MPst) &&
+ i > start && info[i - 1].indic_category() == I_Cat(SM))
+ info[i - 1].indic_position() = info[i].indic_position();
last_pos = (indic_position_t) info[i].indic_position();
}
}
@@ -720,7 +733,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 (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
last = i;
}
@@ -733,14 +746,40 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Sit tight, rock 'n roll! */
hb_stable_sort (info + start, end - start, compare_indic_order);
- /* Find base again */
+
+ /* Find base again; also flip left-matra sequence. */
+ unsigned first_left_matra = end;
+ unsigned last_left_matra = end;
base = end;
for (unsigned int i = start; i < end; i++)
+ {
if (info[i].indic_position() == POS_BASE_C)
{
base = i;
break;
}
+ else if (info[i].indic_position() == POS_PRE_M)
+ {
+ if (first_left_matra == end)
+ first_left_matra = i;
+ last_left_matra = i;
+ }
+ }
+ /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+ if (first_left_matra < last_left_matra)
+ {
+ /* No need to merge clusters, handled later. */
+ buffer->reverse_range (first_left_matra, last_left_matra + 1);
+ /* Reverse back nuktas, etc. */
+ unsigned i = first_left_matra;
+ for (unsigned j = i; j <= last_left_matra; j++)
+ if (FLAG_UNSAFE (info[j].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+ {
+ buffer->reverse_range (i, j + 1);
+ i = j + 1;
+ }
+ }
+
/* Things are out-of-control for post base positions, they may shuffle
* around like crazy. In old-spec mode, we move halants around, so in
* that case merge all clusters after base. Otherwise, check the sort
@@ -851,10 +890,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];
@@ -881,7 +920,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 {
@@ -914,7 +953,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;
}
@@ -946,25 +985,29 @@ initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (!buffer->message (font, "start reordering indic initial"))
- return;
+ return ret;
update_consonant_positions_indic (plan, font, buffer);
- hb_syllabic_insert_dotted_circles (font, buffer,
- indic_broken_cluster,
- OT_DOTTEDCIRCLE,
- OT_Repha,
- POS_END);
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ indic_broken_cluster,
+ I_Cat(DOTTEDCIRCLE),
+ I_Cat(Repha),
+ POS_END))
+ ret = true;
foreach_syllable (buffer, start, end)
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
(void) buffer->message (font, "end reordering indic initial");
+
+ return ret;
}
static void
@@ -980,10 +1023,10 @@ 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 ();
+ hb_codepoint_t virama_glyph = indic_plan->virama_glyph;
if (virama_glyph)
{
for (unsigned int i = start; i < end; i++)
@@ -992,7 +1035,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]);
}
}
@@ -1058,11 +1101,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--;
@@ -1107,7 +1150,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(MPst)) | FLAG (I_Cat(H))))))
new_pos--;
/* If we found no Halant we are done.
@@ -1124,7 +1167,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)
@@ -1197,7 +1240,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;
@@ -1307,7 +1350,8 @@ 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 (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+ {
/* Ok, got it. */
new_reph_pos--;
}
@@ -1367,7 +1411,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(MPst)) | FLAG (I_Cat(H)))))
new_pos--;
}
@@ -1416,11 +1460,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. */
@@ -1431,13 +1474,13 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
-static void
+static bool
final_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
- if (unlikely (!count)) return;
+ if (unlikely (!count)) return false;
if (buffer->message (font, "start reordering indic final")) {
foreach_syllable (buffer, start, end)
@@ -1447,6 +1490,8 @@ final_reordering_indic (const hb_ot_shape_plan_t *plan,
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+
+ return false;
}
@@ -1455,7 +1500,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
@@ -1488,48 +1535,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);
}
@@ -1550,7 +1555,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,
@@ -1558,12 +1563,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_destroy_indic,
preprocess_text_indic,
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,
setup_masks_indic,
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shaper-indic.hh b/src/hb-ot-shaper-indic.hh
new file mode 100644
index 000000000..4f822c26e
--- /dev/null
+++ b/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/src/hb-ot-shaper-khmer-machine.hh b/src/hb-ot-shaper-khmer-machine.hh
new file mode 100644
index 000000000..fd91ee0ca
--- /dev/null
+++ b/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 49 "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 65 "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 (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 287 "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 299 "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 311 "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 368 "hb-ot-shaper-khmer-machine.hh"
+ }
+
+_again:
+ switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+ case 6:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 375 "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/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shaper-khmer-machine.rl
index c9cf33f41..d5d429d67 100644
--- a/src/hb-ot-shape-complex-khmer-machine.rl
+++ b/src/hb-ot-shaper-khmer-machine.rl
@@ -24,11 +24,21 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
+#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,
@@ -44,21 +54,27 @@ enum khmer_syllable_type_t {
%%{
+
+# We use category H for spec category Coeng
+
export C = 1;
export V = 2;
+export H = 4;
export ZWNJ = 5;
export ZWJ = 6;
-export PLACEHOLDER = 11;
-export DOTTEDCIRCLE = 12;
-export Coeng= 14;
-export Ra = 16;
-export Robatic = 20;
-export Xgroup = 21;
-export Ygroup = 22;
-export VAbv = 26;
-export VBlw = 27;
-export VPre = 28;
-export VPst = 29;
+export PLACEHOLDER = 10;
+export DOTTEDCIRCLE = 11;
+export Ra = 15;
+
+export VAbv = 20;
+export VBlw = 21;
+export VPre = 22;
+export VPst = 23;
+
+export Robatic = 25;
+export Xgroup = 26;
+export Ygroup = 27;
+
c = (C | Ra | V);
cn = c.((ZWJ|ZWNJ)?.Robatic)?;
@@ -69,16 +85,16 @@ ygroup = Ygroup*;
# This grammar was experimentally extracted from what Uniscribe allows.
matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?;
-syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup;
+syllable_tail = xgroup matra_group xgroup (H.c)? ygroup;
-broken_cluster = (Coeng.cn)* (Coeng | syllable_tail);
+broken_cluster = Robatic? (H.cn)* (H | syllable_tail);
consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
other = any;
main := |*
consonant_syllable => { found_syllable (khmer_consonant_syllable); };
- broken_cluster => { found_syllable (khmer_broken_cluster); };
+ broken_cluster => { found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
other => { found_syllable (khmer_non_khmer_cluster); };
*|;
@@ -91,10 +107,10 @@ main := |*
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; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
-static void
+inline void
find_syllables_khmer (hb_buffer_t *buffer)
{
unsigned int p, pe, eof, ts, te, act HB_UNUSED;
@@ -116,4 +132,4 @@ find_syllables_khmer (hb_buffer_t *buffer)
#undef found_syllable
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
+#endif /* HB_OT_SHAPER_KHMER_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shaper-khmer.cc
index 778788685..019a28510 100644
--- a/src/hb-ot-shape-complex-khmer.cc
+++ b/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[] =
{
@@ -45,11 +46,11 @@ khmer_features[] =
* These features are applied all at once, before reordering, constrained
* to the syllable.
*/
- {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
- {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
- {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
- {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
- {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
+ {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+ {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once after clearing syllables.
@@ -79,11 +80,20 @@ enum {
KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */
};
-static void
+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 bool
setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -107,14 +117,15 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
*
* https://github.com/harfbuzz/harfbuzz/issues/974
*/
- map->enable_feature (HB_TAG('l','o','c','l'));
- map->enable_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+ map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
for (; i < KHMER_BASIC_FEATURES; i++)
map->add_feature (khmer_features[i]);
- map->add_gsub_pause (_hb_clear_syllables);
+ /* https://github.com/harfbuzz/harfbuzz/issues/3531 */
+ map->add_gsub_pause (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]);
@@ -181,14 +192,16 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_khmer_properties (info[i]);
}
-static void
+static bool
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);
+ return false;
}
@@ -229,11 +242,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];
@@ -261,7 +274,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);
@@ -291,23 +304,27 @@ reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering khmer"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- khmer_broken_cluster,
- OT_DOTTEDCIRCLE,
- OT_Repha);
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ khmer_broken_cluster,
+ K_Cat(DOTTEDCIRCLE),
+ (unsigned) -1))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_khmer (plan, font->face, buffer, start, end);
(void) buffer->message (font, "end reordering khmer");
}
HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
+
+ return ret;
}
@@ -348,7 +365,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,
@@ -356,12 +373,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer =
data_destroy_khmer,
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_khmer,
compose_khmer,
setup_masks_khmer,
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shaper-myanmar-machine.hh b/src/hb-ot-shaper-myanmar-machine.hh
new file mode 100644
index 000000000..87cded4ed
--- /dev/null
+++ b/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 51 "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 76 "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 (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 436 "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 448 "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 460 "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 498 "hb-ot-shaper-myanmar-machine.hh"
+ }
+
+_again:
+ switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
+ case 1:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 505 "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/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shaper-myanmar-machine.rl
index 2e6ac783f..db6a44c60 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shaper-myanmar-machine.rl
@@ -24,14 +24,25 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+#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_punctuation_cluster,
myanmar_broken_cluster,
myanmar_non_myanmar_cluster,
};
@@ -45,32 +56,38 @@ enum myanmar_syllable_type_t {
%%{
-export A = 10;
-export As = 18;
+
+# Spec category D is folded into GB; D0 is not implemented by Uniscribe and as such folded into D
+# Spec category P is folded into GB
+
export C = 1;
-export D = 32;
-export D0 = 20;
-export DB = 3;
-export GB = 11;
-export H = 4;
export IV = 2;
-export MH = 21;
-export ML = 33;
-export MR = 22;
-export MW = 23;
-export MY = 24;
-export PT = 25;
-export V = 8;
-export VAbv = 26;
-export VBlw = 27;
-export VPre = 28;
-export VPst = 29;
-export VS = 30;
-export ZWJ = 6;
+export DB = 3; # Dot below = OT_N
+export H = 4;
export ZWNJ = 5;
-export Ra = 16;
-export P = 31;
-export CS = 19;
+export ZWJ = 6;
+export SM = 8; # Visarga and Shan tones
+export GB = 10; # = OT_PLACEHOLDER
+export DOTTEDCIRCLE = 11;
+export A = 9;
+export Ra = 15;
+export CS = 18;
+
+export VAbv = 20;
+export VBlw = 21;
+export VPre = 22;
+export VPst = 23;
+
+# 32+ are for Myanmar-specific values
+export As = 32; # Asat
+export MH = 35; # Medial Ha
+export MR = 36; # Medial Ra
+export MW = 37; # Medial Wa, Shan Wa
+export MY = 38; # Medial Ya, Mon Na, Mon Ma
+export PT = 39; # Pwo and other tones
+export VS = 40; # Variation selectors
+export ML = 41; # Medial Mon La
+
j = ZWJ|ZWNJ; # Joiners
k = (Ra As H); # Kinzi
@@ -82,19 +99,17 @@ main_vowel_group = (VPre.VS?)* VAbv* VBlw* A* (DB As?)?;
post_vowel_group = VPst MH? ML? As* VAbv* A* (DB As?)?;
pwo_tone_group = PT A* DB? As?;
-complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* V* j?;
+complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* SM* j?;
syllable_tail = (H (c|IV).VS?)* (H | complex_syllable_tail);
-consonant_syllable = (k|CS)? (c|IV|D|GB).VS? syllable_tail;
-punctuation_cluster = P V;
+consonant_syllable = (k|CS)? (c|IV|GB|DOTTEDCIRCLE).VS? syllable_tail;
broken_cluster = k? VS? syllable_tail;
other = any;
main := |*
consonant_syllable => { found_syllable (myanmar_consonant_syllable); };
j => { found_syllable (myanmar_non_myanmar_cluster); };
- punctuation_cluster => { found_syllable (myanmar_punctuation_cluster); };
- broken_cluster => { found_syllable (myanmar_broken_cluster); };
+ broken_cluster => { found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
other => { found_syllable (myanmar_non_myanmar_cluster); };
*|;
@@ -107,10 +122,10 @@ main := |*
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; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
-static void
+inline void
find_syllables_myanmar (hb_buffer_t *buffer)
{
unsigned int p, pe, eof, ts, te, act HB_UNUSED;
@@ -132,4 +147,4 @@ find_syllables_myanmar (hb_buffer_t *buffer)
#undef found_syllable
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
+#endif /* HB_OT_SHAPER_MYANMAR_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shaper-myanmar.cc
index e6ae75e8f..1b2a085a8 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/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,11 +64,45 @@ myanmar_other_features[] =
HB_TAG('p','s','t','s'),
};
-static void
+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 bool
setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -79,21 +115,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_myanmar);
- map->enable_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
- map->enable_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->add_gsub_pause (reorder_myanmar);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
{
- map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
+ map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (nullptr);
}
-
- map->add_gsub_pause (_hb_clear_syllables);
+ 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);
@@ -107,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;
@@ -116,14 +150,16 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_myanmar_properties (info[i]);
}
-static void
+static bool
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);
+ return false;
}
static int
@@ -132,7 +168,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;
}
@@ -151,9 +187,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;
@@ -165,7 +201,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;
@@ -190,39 +226,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;
@@ -234,6 +271,33 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
/* Sit tight, rock 'n roll! */
buffer->sort (start, end, compare_myanmar_order);
+
+ /* Flip left-matra sequence. */
+ unsigned first_left_matra = end;
+ unsigned last_left_matra = end;
+ for (unsigned int i = start; i < end; i++)
+ {
+ if (info[i].myanmar_position() == POS_PRE_M)
+ {
+ if (first_left_matra == end)
+ first_left_matra = i;
+ last_left_matra = i;
+ }
+ }
+ /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+ if (first_left_matra < last_left_matra)
+ {
+ /* No need to merge clusters, done already? */
+ buffer->reverse_range (first_left_matra, last_left_matra + 1);
+ /* Reverse back VS, etc. */
+ unsigned i = first_left_matra;
+ for (unsigned j = i; j <= last_left_matra; j++)
+ if (info[j].myanmar_category() == M_Cat(VPre))
+ {
+ buffer->reverse_range (i, j + 1);
+ i = j + 1;
+ }
+ }
}
static void
@@ -250,22 +314,23 @@ 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;
}
}
-static void
+static bool
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering myanmar"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- myanmar_broken_cluster,
- OT_GB);
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ myanmar_broken_cluster,
+ M_Cat(DOTTEDCIRCLE)))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_myanmar (plan, font->face, buffer, start, end);
@@ -274,10 +339,12 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan,
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+
+ return ret;
}
-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 */
@@ -285,21 +352,22 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
nullptr, /* decompose */
nullptr, /* compose */
setup_masks_myanmar,
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
/* 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 */
@@ -307,15 +375,16 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
+#endif
#endif
diff --git a/src/hb-ot-shape-complex-syllabic.cc b/src/hb-ot-shaper-syllabic.cc
index 5a08f878d..89226ae4a 100644
--- a/src/hb-ot-shape-complex-syllabic.cc
+++ b/src/hb-ot-shaper-syllabic.cc
@@ -26,10 +26,10 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-syllabic.hh"
+#include "hb-ot-shaper-syllabic.hh"
-void
+bool
hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
@@ -38,32 +38,19 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
int dottedcircle_position)
{
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))
- return;
-
+ return false;
+ if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
+ return false;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
+ return false;
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 ();
}
@@ -96,7 +83,17 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
else
(void) buffer->next_glyph ();
}
- buffer->swap_buffers ();
+ buffer->sync ();
+ return true;
+}
+
+HB_INTERNAL bool
+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);
+ return false;
}
diff --git a/src/hb-ot-shape-complex-syllabic.hh b/src/hb-ot-shaper-syllabic.hh
index b901a660d..f240ad1c2 100644
--- a/src/hb-ot-shape-complex-syllabic.hh
+++ b/src/hb-ot-shaper-syllabic.hh
@@ -22,15 +22,15 @@
* 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
+HB_INTERNAL bool
hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
@@ -38,5 +38,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
int repha_category = -1,
int dottedcircle_position = -1);
+HB_INTERNAL bool
+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/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shaper-thai.cc
index 4c3068173..6cd67cde3 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/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 */
@@ -98,9 +98,9 @@ static hb_codepoint_t
thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
{
struct thai_pua_mapping_t {
- hb_codepoint_t u;
- hb_codepoint_t win_pua;
- hb_codepoint_t mac_pua;
+ uint16_t u;
+ uint16_t win_pua;
+ uint16_t mac_pua;
} const *pua_mappings = nullptr;
static const thai_pua_mapping_t SD_mappings[] = {
{0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
@@ -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)
@@ -364,14 +364,14 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->merge_out_clusters (start - 1, end);
}
}
- buffer->swap_buffers ();
+ buffer->sync ();
/* If font has Thai GSUB, we are done. */
if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
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 */
@@ -379,12 +379,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
nullptr, /* data_destroy */
preprocess_text_thai,
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
false,/* fallback_position */
};
diff --git a/src/hb-ot-shaper-use-machine.hh b/src/hb-ot-shaper-use-machine.hh
new file mode 100644
index 000000000..f2fbdb725
--- /dev/null
+++ b/src/hb-ot-shaper-use-machine.hh
@@ -0,0 +1,1080 @@
+
+#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 54 "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 96 "hb-ot-shaper-use-machine.hh"
+static const unsigned char _use_syllable_machine_trans_keys[] = {
+ 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
+ 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
+ 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
+ 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 11u, 53u, 14u, 42u, 14u, 42u, 11u, 53u,
+ 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u,
+ 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u,
+ 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u,
+ 1u, 14u, 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u,
+ 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u,
+ 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u,
+ 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u,
+ 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
+ 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
+ 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
+ 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 11u, 53u,
+ 14u, 42u, 14u, 42u, 1u, 5u, 14u, 52u, 14u, 52u, 14u, 51u, 0
+};
+
+static const char _use_syllable_machine_key_spans[] = {
+ 54, 43, 43, 53, 35, 34, 34, 34,
+ 33, 33, 1, 35, 35, 35, 14, 35,
+ 40, 40, 40, 40, 42, 40, 42, 42,
+ 42, 43, 14, 48, 43, 29, 29, 43,
+ 43, 53, 35, 34, 34, 34, 33, 33,
+ 1, 35, 35, 35, 14, 35, 40, 40,
+ 40, 40, 42, 40, 42, 42, 42, 43,
+ 14, 14, 48, 2, 11, 43, 43, 53,
+ 35, 34, 34, 34, 33, 33, 1, 35,
+ 35, 35, 14, 35, 40, 40, 40, 40,
+ 42, 40, 42, 42, 42, 43, 14, 14,
+ 48, 43, 43, 53, 35, 34, 34, 34,
+ 33, 33, 1, 35, 35, 35, 14, 35,
+ 40, 40, 40, 40, 42, 40, 42, 42,
+ 42, 43, 14, 48, 11, 2, 53, 43,
+ 29, 29, 5, 39, 39, 38
+};
+
+static const short _use_syllable_machine_index_offsets[] = {
+ 0, 55, 99, 143, 197, 233, 268, 303,
+ 338, 372, 406, 408, 444, 480, 516, 531,
+ 567, 608, 649, 690, 731, 774, 815, 858,
+ 901, 944, 988, 1003, 1052, 1096, 1126, 1156,
+ 1200, 1244, 1298, 1334, 1369, 1404, 1439, 1473,
+ 1507, 1509, 1545, 1581, 1617, 1632, 1668, 1709,
+ 1750, 1791, 1832, 1875, 1916, 1959, 2002, 2045,
+ 2089, 2104, 2119, 2168, 2171, 2183, 2227, 2271,
+ 2325, 2361, 2396, 2431, 2466, 2500, 2534, 2536,
+ 2572, 2608, 2644, 2659, 2695, 2736, 2777, 2818,
+ 2859, 2902, 2943, 2986, 3029, 3072, 3116, 3131,
+ 3146, 3195, 3239, 3283, 3337, 3373, 3408, 3443,
+ 3478, 3512, 3546, 3548, 3584, 3620, 3656, 3671,
+ 3707, 3748, 3789, 3830, 3871, 3914, 3955, 3998,
+ 4041, 4084, 4128, 4143, 4192, 4204, 4207, 4261,
+ 4305, 4335, 4365, 4371, 4411, 4451
+};
+
+static const unsigned char _use_syllable_machine_indicies[] = {
+ 0, 1, 2, 2, 3, 4, 2, 2,
+ 2, 2, 2, 5, 6, 7, 8, 2,
+ 2, 2, 9, 2, 2, 2, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 2, 24, 25, 26,
+ 2, 27, 28, 29, 30, 31, 32, 33,
+ 30, 34, 2, 35, 2, 36, 2, 38,
+ 39, 37, 40, 37, 37, 37, 37, 37,
+ 37, 37, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54,
+ 37, 55, 56, 57, 37, 58, 59, 37,
+ 60, 61, 62, 63, 60, 37, 37, 37,
+ 37, 64, 37, 38, 39, 37, 40, 37,
+ 37, 37, 37, 37, 37, 37, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 51,
+ 51, 52, 53, 54, 37, 55, 56, 57,
+ 37, 37, 37, 37, 60, 61, 62, 63,
+ 60, 37, 37, 37, 37, 64, 37, 38,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 42, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 55, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 37, 37, 37, 42, 37, 40, 37, 37,
+ 37, 37, 37, 37, 37, 37, 42, 43,
+ 44, 45, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 55, 56, 57, 37,
+ 37, 37, 37, 37, 61, 62, 63, 65,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 43, 44, 45, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 61, 62, 63, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 61, 62, 63, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 45, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 61, 62,
+ 63, 37, 40, 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,
+ 37, 61, 62, 37, 40, 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, 37, 37, 62, 37, 40, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 66, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 40, 37, 40, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 43, 44, 45,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 61, 62, 63, 65, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 37, 37, 37, 37,
+ 37, 37, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 37, 61, 62,
+ 63, 65, 37, 37, 37, 37, 42, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 42, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 52, 53, 54, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 37, 37, 37, 42,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 37, 42, 43, 44, 45, 37, 37,
+ 37, 37, 37, 37, 37, 53, 54, 37,
+ 55, 56, 57, 37, 37, 37, 37, 37,
+ 61, 62, 63, 65, 37, 37, 37, 37,
+ 42, 37, 40, 37, 37, 37, 37, 37,
+ 37, 37, 37, 42, 43, 44, 45, 37,
+ 37, 37, 37, 37, 37, 37, 37, 54,
+ 37, 55, 56, 57, 37, 37, 37, 37,
+ 37, 61, 62, 63, 65, 37, 37, 37,
+ 37, 42, 37, 67, 37, 40, 37, 37,
+ 37, 37, 37, 37, 37, 41, 42, 43,
+ 44, 45, 37, 47, 48, 37, 37, 37,
+ 52, 53, 54, 37, 55, 56, 57, 37,
+ 37, 37, 37, 37, 61, 62, 63, 65,
+ 37, 37, 37, 37, 42, 37, 40, 37,
+ 37, 37, 37, 37, 37, 37, 37, 42,
+ 43, 44, 45, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 55, 56, 57,
+ 37, 37, 37, 37, 37, 61, 62, 63,
+ 65, 37, 37, 37, 37, 42, 37, 67,
+ 37, 40, 37, 37, 37, 37, 37, 37,
+ 37, 41, 42, 43, 44, 45, 37, 37,
+ 48, 37, 37, 37, 52, 53, 54, 37,
+ 55, 56, 57, 37, 37, 37, 37, 37,
+ 61, 62, 63, 65, 37, 37, 37, 37,
+ 42, 37, 67, 37, 40, 37, 37, 37,
+ 37, 37, 37, 37, 41, 42, 43, 44,
+ 45, 37, 37, 37, 37, 37, 37, 52,
+ 53, 54, 37, 55, 56, 57, 37, 37,
+ 37, 37, 37, 61, 62, 63, 65, 37,
+ 37, 37, 37, 42, 37, 67, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 46, 47, 48, 37,
+ 37, 37, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 37, 61, 62,
+ 63, 65, 37, 37, 37, 37, 42, 37,
+ 38, 39, 37, 40, 37, 37, 37, 37,
+ 37, 37, 37, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 37, 51, 52, 53,
+ 54, 37, 55, 56, 57, 37, 37, 37,
+ 37, 60, 61, 62, 63, 60, 37, 37,
+ 37, 37, 64, 37, 38, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 40, 37, 38, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 40, 37, 37, 37, 37, 37, 37, 37,
+ 37, 42, 43, 44, 45, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 55,
+ 56, 57, 37, 37, 37, 37, 37, 61,
+ 62, 63, 65, 37, 38, 39, 37, 40,
+ 37, 37, 37, 37, 37, 37, 37, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 37, 55, 56,
+ 57, 37, 37, 37, 37, 60, 61, 62,
+ 63, 60, 37, 37, 37, 37, 64, 37,
+ 40, 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, 58, 59, 37, 40, 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, 59, 37, 69, 70, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 1, 81, 82, 83, 84, 68, 85, 86,
+ 87, 68, 68, 68, 68, 88, 89, 90,
+ 91, 92, 68, 68, 68, 68, 93, 68,
+ 69, 70, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 81, 82, 83,
+ 84, 68, 85, 86, 87, 68, 68, 68,
+ 68, 88, 89, 90, 91, 92, 68, 68,
+ 68, 68, 93, 68, 69, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 73, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 85, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 68, 68, 68,
+ 73, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 73, 74, 75, 76, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 85, 86, 87, 68, 68, 68, 68,
+ 68, 89, 90, 91, 94, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 74, 75, 76, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 89, 90, 91, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 76, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 89, 90, 91, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 89, 90,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 90, 68, 71, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 85, 86, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 96, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 97, 95,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 74, 75, 76, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 89,
+ 90, 91, 94, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 72, 73, 74, 75,
+ 76, 68, 68, 68, 68, 68, 68, 82,
+ 83, 84, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 68, 68, 68, 73, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 73, 74,
+ 75, 76, 68, 68, 68, 68, 68, 68,
+ 82, 83, 84, 68, 85, 86, 87, 68,
+ 68, 68, 68, 68, 89, 90, 91, 94,
+ 68, 68, 68, 68, 73, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 73,
+ 74, 75, 76, 68, 68, 68, 68, 68,
+ 68, 68, 83, 84, 68, 85, 86, 87,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 94, 68, 68, 68, 68, 73, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 73, 74, 75, 76, 68, 68, 68, 68,
+ 68, 68, 68, 68, 84, 68, 85, 86,
+ 87, 68, 68, 68, 68, 68, 89, 90,
+ 91, 94, 68, 68, 68, 68, 73, 68,
+ 98, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 72, 73, 74, 75, 76, 68,
+ 78, 79, 68, 68, 68, 82, 83, 84,
+ 68, 85, 86, 87, 68, 68, 68, 68,
+ 68, 89, 90, 91, 94, 68, 68, 68,
+ 68, 73, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 68, 73, 74, 75, 76,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 85, 86, 87, 68, 68, 68,
+ 68, 68, 89, 90, 91, 94, 68, 68,
+ 68, 68, 73, 68, 98, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 72, 73,
+ 74, 75, 76, 68, 68, 79, 68, 68,
+ 68, 82, 83, 84, 68, 85, 86, 87,
+ 68, 68, 68, 68, 68, 89, 90, 91,
+ 94, 68, 68, 68, 68, 73, 68, 98,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 72, 73, 74, 75, 76, 68, 68,
+ 68, 68, 68, 68, 82, 83, 84, 68,
+ 85, 86, 87, 68, 68, 68, 68, 68,
+ 89, 90, 91, 94, 68, 68, 68, 68,
+ 73, 68, 98, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 72, 73, 74, 75,
+ 76, 77, 78, 79, 68, 68, 68, 82,
+ 83, 84, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 68, 68, 68, 73, 68, 69, 70, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 68, 81, 82, 83, 84, 68, 85,
+ 86, 87, 68, 68, 68, 68, 88, 89,
+ 90, 91, 92, 68, 68, 68, 68, 93,
+ 68, 69, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 100, 99,
+ 69, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 97, 95, 69,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 73, 74, 75,
+ 76, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 85, 86, 87, 68, 68,
+ 68, 68, 68, 89, 90, 91, 94, 68,
+ 102, 103, 101, 3, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 105, 104, 106,
+ 107, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 120, 121,
+ 68, 122, 123, 124, 68, 58, 59, 68,
+ 125, 126, 127, 128, 129, 68, 68, 68,
+ 68, 130, 68, 106, 107, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 118,
+ 118, 119, 120, 121, 68, 122, 123, 124,
+ 68, 68, 68, 68, 125, 126, 127, 128,
+ 129, 68, 68, 68, 68, 130, 68, 106,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 109, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 122, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 68, 68, 68, 109, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 109, 110,
+ 111, 112, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 122, 123, 124, 68,
+ 68, 68, 68, 68, 126, 127, 128, 131,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 110, 111, 112, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 126, 127, 128, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 126, 127, 128, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 112, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 126, 127,
+ 128, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 126, 127, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 127, 68, 71, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 122,
+ 123, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 132, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 97, 95, 71, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 110, 111, 112,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 126, 127, 128, 131, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 108,
+ 109, 110, 111, 112, 68, 68, 68, 68,
+ 68, 68, 119, 120, 121, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 68, 68, 68, 109, 68,
+ 71, 68, 68, 68, 68, 68, 68, 68,
+ 68, 109, 110, 111, 112, 68, 68, 68,
+ 68, 68, 68, 119, 120, 121, 68, 122,
+ 123, 124, 68, 68, 68, 68, 68, 126,
+ 127, 128, 131, 68, 68, 68, 68, 109,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 68, 109, 110, 111, 112, 68, 68,
+ 68, 68, 68, 68, 68, 120, 121, 68,
+ 122, 123, 124, 68, 68, 68, 68, 68,
+ 126, 127, 128, 131, 68, 68, 68, 68,
+ 109, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 68, 109, 110, 111, 112, 68,
+ 68, 68, 68, 68, 68, 68, 68, 121,
+ 68, 122, 123, 124, 68, 68, 68, 68,
+ 68, 126, 127, 128, 131, 68, 68, 68,
+ 68, 109, 68, 133, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 108, 109, 110,
+ 111, 112, 68, 114, 115, 68, 68, 68,
+ 119, 120, 121, 68, 122, 123, 124, 68,
+ 68, 68, 68, 68, 126, 127, 128, 131,
+ 68, 68, 68, 68, 109, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 68, 109,
+ 110, 111, 112, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 122, 123, 124,
+ 68, 68, 68, 68, 68, 126, 127, 128,
+ 131, 68, 68, 68, 68, 109, 68, 133,
+ 68, 71, 68, 68, 68, 68, 68, 68,
+ 68, 108, 109, 110, 111, 112, 68, 68,
+ 115, 68, 68, 68, 119, 120, 121, 68,
+ 122, 123, 124, 68, 68, 68, 68, 68,
+ 126, 127, 128, 131, 68, 68, 68, 68,
+ 109, 68, 133, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 108, 109, 110, 111,
+ 112, 68, 68, 68, 68, 68, 68, 119,
+ 120, 121, 68, 122, 123, 124, 68, 68,
+ 68, 68, 68, 126, 127, 128, 131, 68,
+ 68, 68, 68, 109, 68, 133, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 108,
+ 109, 110, 111, 112, 113, 114, 115, 68,
+ 68, 68, 119, 120, 121, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 68, 68, 68, 109, 68,
+ 106, 107, 68, 71, 68, 68, 68, 68,
+ 68, 68, 68, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 68, 118, 119, 120,
+ 121, 68, 122, 123, 124, 68, 68, 68,
+ 68, 125, 126, 127, 128, 129, 68, 68,
+ 68, 68, 130, 68, 106, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 100, 99, 106, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95,
+ 97, 95, 106, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 71,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 109, 110, 111, 112, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 122, 123,
+ 124, 68, 68, 68, 68, 68, 126, 127,
+ 128, 131, 68, 106, 107, 68, 71, 68,
+ 68, 68, 68, 68, 68, 68, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 68, 122, 123, 124,
+ 68, 68, 68, 68, 125, 126, 127, 128,
+ 129, 68, 68, 68, 68, 130, 68, 5,
+ 6, 134, 8, 134, 134, 134, 134, 134,
+ 134, 134, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 20, 20, 21, 22, 23,
+ 134, 24, 25, 26, 134, 134, 134, 134,
+ 30, 31, 32, 33, 30, 134, 134, 134,
+ 134, 36, 134, 5, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 11, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 24,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 134, 134, 134, 11,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 134, 11, 12, 13, 14, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 24, 25, 26, 134, 134, 134, 134, 134,
+ 31, 32, 33, 135, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 12,
+ 13, 14, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 31, 32, 33, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 31,
+ 32, 33, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 14,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 31, 32, 33, 134, 8, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 31, 32, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 32, 134, 8, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 136, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 8, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 12, 13, 14, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 31, 32,
+ 33, 135, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 10, 11, 12, 13, 14,
+ 134, 134, 134, 134, 134, 134, 21, 22,
+ 23, 134, 24, 25, 26, 134, 134, 134,
+ 134, 134, 31, 32, 33, 135, 134, 134,
+ 134, 134, 11, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 11, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 21,
+ 22, 23, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 134, 134, 134, 11, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 134, 11, 12,
+ 13, 14, 134, 134, 134, 134, 134, 134,
+ 134, 22, 23, 134, 24, 25, 26, 134,
+ 134, 134, 134, 134, 31, 32, 33, 135,
+ 134, 134, 134, 134, 11, 134, 8, 134,
+ 134, 134, 134, 134, 134, 134, 134, 11,
+ 12, 13, 14, 134, 134, 134, 134, 134,
+ 134, 134, 134, 23, 134, 24, 25, 26,
+ 134, 134, 134, 134, 134, 31, 32, 33,
+ 135, 134, 134, 134, 134, 11, 134, 137,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 10, 11, 12, 13, 14, 134, 16,
+ 17, 134, 134, 134, 21, 22, 23, 134,
+ 24, 25, 26, 134, 134, 134, 134, 134,
+ 31, 32, 33, 135, 134, 134, 134, 134,
+ 11, 134, 8, 134, 134, 134, 134, 134,
+ 134, 134, 134, 11, 12, 13, 14, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 24, 25, 26, 134, 134, 134, 134,
+ 134, 31, 32, 33, 135, 134, 134, 134,
+ 134, 11, 134, 137, 134, 8, 134, 134,
+ 134, 134, 134, 134, 134, 10, 11, 12,
+ 13, 14, 134, 134, 17, 134, 134, 134,
+ 21, 22, 23, 134, 24, 25, 26, 134,
+ 134, 134, 134, 134, 31, 32, 33, 135,
+ 134, 134, 134, 134, 11, 134, 137, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 10, 11, 12, 13, 14, 134, 134, 134,
+ 134, 134, 134, 21, 22, 23, 134, 24,
+ 25, 26, 134, 134, 134, 134, 134, 31,
+ 32, 33, 135, 134, 134, 134, 134, 11,
+ 134, 137, 134, 8, 134, 134, 134, 134,
+ 134, 134, 134, 10, 11, 12, 13, 14,
+ 15, 16, 17, 134, 134, 134, 21, 22,
+ 23, 134, 24, 25, 26, 134, 134, 134,
+ 134, 134, 31, 32, 33, 135, 134, 134,
+ 134, 134, 11, 134, 5, 6, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 134, 20, 21, 22, 23, 134, 24, 25,
+ 26, 134, 134, 134, 134, 30, 31, 32,
+ 33, 30, 134, 134, 134, 134, 36, 134,
+ 5, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 8, 134, 5,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 8, 134, 134, 134,
+ 134, 134, 134, 134, 134, 11, 12, 13,
+ 14, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 24, 25, 26, 134, 134,
+ 134, 134, 134, 31, 32, 33, 135, 134,
+ 138, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 8, 134, 7, 8, 134, 1,
+ 134, 134, 134, 1, 134, 134, 134, 134,
+ 134, 5, 6, 7, 8, 134, 134, 134,
+ 134, 134, 134, 134, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 134, 24, 25, 26, 134, 27,
+ 28, 134, 30, 31, 32, 33, 30, 134,
+ 134, 134, 134, 36, 134, 5, 6, 134,
+ 8, 134, 134, 134, 134, 134, 134, 134,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 134, 24,
+ 25, 26, 134, 134, 134, 134, 30, 31,
+ 32, 33, 30, 134, 134, 134, 134, 36,
+ 134, 8, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 27, 28, 134, 8,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 28, 134, 1, 139, 139,
+ 139, 1, 139, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 142,
+ 140, 34, 140, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 34, 142,
+ 140, 142, 140, 141, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 34, 140,
+ 35, 140, 0
+};
+
+static const char _use_syllable_machine_trans_targs[] = {
+ 1, 31, 0, 59, 61, 90, 91, 116,
+ 0, 118, 104, 92, 93, 94, 95, 108,
+ 110, 111, 112, 119, 113, 105, 106, 107,
+ 99, 100, 101, 120, 121, 122, 114, 96,
+ 97, 98, 123, 125, 115, 0, 2, 3,
+ 0, 16, 4, 5, 6, 7, 20, 22,
+ 23, 24, 28, 25, 17, 18, 19, 11,
+ 12, 13, 29, 30, 26, 8, 9, 10,
+ 27, 14, 15, 21, 0, 32, 33, 0,
+ 46, 34, 35, 36, 37, 50, 52, 53,
+ 54, 55, 47, 48, 49, 41, 42, 43,
+ 56, 38, 39, 40, 57, 58, 44, 0,
+ 45, 0, 51, 0, 0, 0, 60, 0,
+ 0, 0, 62, 63, 76, 64, 65, 66,
+ 67, 80, 82, 83, 84, 89, 85, 77,
+ 78, 79, 71, 72, 73, 86, 68, 69,
+ 70, 87, 88, 74, 75, 81, 0, 102,
+ 103, 109, 117, 0, 0, 0, 124
+};
+
+static const char _use_syllable_machine_trans_actions[] = {
+ 0, 0, 3, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 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, 0,
+ 0, 0, 0, 0, 7, 0, 0, 8,
+ 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, 10, 0, 11, 12, 13, 0, 14,
+ 15, 16, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 17, 0,
+ 0, 0, 0, 18, 19, 20, 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,
+ 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,
+ 0, 0, 0, 0, 0, 0
+};
+
+static const short _use_syllable_machine_eof_trans[] = {
+ 0, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 96, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 100, 96, 69, 102, 105, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 96, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 100, 96,
+ 69, 69, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 135, 140, 141, 141, 141
+};
+
+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 (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 922 "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 931 "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 943 "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 12:
+#line 170 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_virama_terminated_cluster); }}
+ break;
+ case 10:
+#line 171 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_sakot_terminated_cluster); }}
+ break;
+ case 8:
+#line 172 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_standard_cluster); }}
+ break;
+ case 16:
+#line 173 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }}
+ break;
+ case 14:
+#line 174 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_numeral_cluster); }}
+ break;
+ case 6:
+#line 175 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_symbol_cluster); }}
+ break;
+ case 20:
+#line 176 "hb-ot-shaper-use-machine.rl"
+ {te = p+1;{ found_syllable (use_hieroglyph_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 170 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
+ break;
+ case 9:
+#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 15:
+#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 19:
+#line 176 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
+ break;
+ case 17:
+#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 18:
+#line 178 "hb-ot-shaper-use-machine.rl"
+ {te = p;p--;{ found_syllable (use_non_cluster); }}
+ break;
+#line 1014 "hb-ot-shaper-use-machine.hh"
+ }
+
+_again:
+ switch ( _use_syllable_machine_to_state_actions[cs] ) {
+ case 1:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 1021 "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/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shaper-use-machine.rl
index 9e0d98d40..8ace1f026 100644
--- a/src/hb-ot-shape-complex-use-machine.rl
+++ b/src/hb-ot-shaper-use-machine.rl
@@ -26,15 +26,15 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+#ifndef HB_OT_SHAPER_USE_MACHINE_HH
+#define HB_OT_SHAPER_USE_MACHINE_HH
#include "hb.hh"
-#include "hb-ot-shape-complex-syllabic.hh"
+#include "hb-ot-shaper-syllabic.hh"
/* buffer var allocations */
-#define use_category() complex_var_u8_category()
+#define use_category() ot_shaper_var_u8_category()
#define USE(Cat) use_syllable_machine_ex_##Cat
@@ -73,14 +73,16 @@ export H = 12; # HALANT
export HN = 13; # HALANT_NUM
export ZWNJ = 14; # Zero width non-joiner
+export WJ = 16; # Word joiner
export R = 18; # REPHA
export CS = 43; # CONS_WITH_STACKER
-export HVM = 44; # HALANT_OR_VOWEL_MODIFIER
+export IS = 44; # INVISIBLE_STACKER
export Sk = 48; # SAKOT
export G = 49; # HIEROGLYPH
export J = 50; # HIEROGLYPH_JOINER
export SB = 51; # HIEROGLYPH_SEGMENT_BEGIN
export SE = 52; # HIEROGLYPH_SEGMENT_END
+export HVM = 53; # HALANT_OR_VOWEL_MODIFIER
export FAbv = 24; # CONS_FINAL_ABOVE
export FBlw = 25; # CONS_FINAL_BELOW
@@ -106,11 +108,11 @@ export FMBlw = 46; # CONS_FINAL_MOD UIPC = Bottom
export FMPst = 47; # CONS_FINAL_MOD UIPC = Not_Applicable
-h = H | HVM | Sk;
+h = H | HVM | IS | Sk;
consonant_modifiers = CMAbv* CMBlw* ((h B | SUB) CMAbv? CMBlw*)*;
medial_consonants = MPre? MAbv? MBlw? MPst?;
-dependent_vowels = VPre* VAbv* VBlw* VPst*;
+dependent_vowels = VPre* VAbv* VBlw* VPst* | H;
vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
final_consonants = FAbv* FBlw* FPst*;
final_modifiers = FMAbv* FMBlw* | FMPst?;
@@ -134,7 +136,7 @@ symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
virama_terminated_cluster_tail =
consonant_modifiers
- h
+ IS
;
virama_terminated_cluster =
complex_syllable_start
@@ -152,26 +154,27 @@ standard_cluster =
complex_syllable_start
complex_syllable_tail
;
+tail = complex_syllable_tail | sakot_terminated_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail;
broken_cluster =
R?
- (complex_syllable_tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail | sakot_terminated_cluster_tail)
+ (tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail)
;
number_joiner_terminated_cluster = N number_joiner_terminated_cluster_tail;
numeral_cluster = N numeral_cluster_tail?;
-symbol_cluster = (O | GB) symbol_cluster_tail?;
+symbol_cluster = (O | GB) tail?;
hieroglyph_cluster = SB+ | SB* G SE* (J SE* (G SE*)?)*;
other = any;
main := |*
- virama_terminated_cluster => { found_syllable (use_virama_terminated_cluster); };
- sakot_terminated_cluster => { found_syllable (use_sakot_terminated_cluster); };
- standard_cluster => { found_syllable (use_standard_cluster); };
- number_joiner_terminated_cluster => { found_syllable (use_number_joiner_terminated_cluster); };
- numeral_cluster => { found_syllable (use_numeral_cluster); };
- symbol_cluster => { found_syllable (use_symbol_cluster); };
- hieroglyph_cluster => { found_syllable (use_hieroglyph_cluster); };
- broken_cluster => { found_syllable (use_broken_cluster); };
+ virama_terminated_cluster ZWNJ? => { found_syllable (use_virama_terminated_cluster); };
+ sakot_terminated_cluster ZWNJ? => { found_syllable (use_sakot_terminated_cluster); };
+ standard_cluster ZWNJ? => { found_syllable (use_standard_cluster); };
+ number_joiner_terminated_cluster ZWNJ? => { found_syllable (use_number_joiner_terminated_cluster); };
+ numeral_cluster ZWNJ? => { found_syllable (use_numeral_cluster); };
+ symbol_cluster ZWNJ? => { found_syllable (use_symbol_cluster); };
+ hieroglyph_cluster ZWNJ? => { found_syllable (use_hieroglyph_cluster); };
+ broken_cluster ZWNJ? => { found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
other => { found_syllable (use_non_cluster); };
*|;
@@ -184,7 +187,7 @@ main := |*
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; \
+ if (syllable_serial == 16) syllable_serial = 1; \
} HB_STMT_END
@@ -194,7 +197,9 @@ struct machine_index_t :
typename Iter::item_t>
{
machine_index_t (const Iter& it) : it (it) {}
- machine_index_t (const machine_index_t& o) : it (o.it) {}
+ machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
+ typename Iter::item_t> (),
+ it (o.it), is_null (o.is_null) {}
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
@@ -206,14 +211,28 @@ struct machine_index_t :
void __forward__ (unsigned n) { it += n; }
void __prev__ () { --it; }
void __rewind__ (unsigned n) { it -= n; }
+
void operator = (unsigned n)
- { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
- void operator = (const machine_index_t& o) { *this = (*o.it).first; }
- bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
+ {
+ assert (n == 0);
+ is_null = true;
+ }
+ explicit operator bool () { return !is_null; }
+
+ void operator = (const machine_index_t& o)
+ {
+ is_null = o.is_null;
+ unsigned index = (*it).first;
+ unsigned n = (*o.it).first;
+ if (index < n) it += n - index; else if (index > n) it -= index - n;
+ }
+ bool operator == (const machine_index_t& o) const
+ { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; }
bool operator != (const machine_index_t& o) const { return !(*this == o); }
private:
Iter it;
+ bool is_null = false;
};
struct
{
@@ -229,7 +248,7 @@ HB_FUNCOBJ (machine_index);
static bool
not_ccs_default_ignorable (const hb_glyph_info_t &i)
-{ return !(i.use_category() == USE(CGJ) && _hb_glyph_info_is_default_ignorable (&i)); }
+{ return i.use_category() != USE(CGJ); }
static inline void
find_syllables_use (hb_buffer_t *buffer)
@@ -270,4 +289,4 @@ find_syllables_use (hb_buffer_t *buffer)
#undef found_syllable
-#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
+#endif /* HB_OT_SHAPER_USE_MACHINE_HH */
diff --git a/src/hb-ot-shaper-use-table.hh b/src/hb-ot-shaper-use-table.hh
new file mode 100644
index 000000000..6b6b552ee
--- /dev/null
+++ b/src/hb-ot-shaper-use-table.hh
@@ -0,0 +1,674 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # IndicPositionalCategory-15.0.0.txt
+ * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
+ * # ArabicShaping-15.0.0.txt
+ * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
+ * # DerivedCoreProperties-15.0.0.txt
+ * # Date: 2022-08-05, 22:17:05 GMT
+ * # Blocks-15.0.0.txt
+ * # Date: 2022-01-28, 20:58:00 GMT [KW]
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 GMT
+ * # Override values For Indic_Syllabic_Category
+ * # Not derivable
+ * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
+ * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
+ * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
+ * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
+ * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * # Override values For Indic_Positional_Category
+ * # Not derivable
+ * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
+ * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
+ * # Ammended for Unicode 10.0 by Andrew Glass 2018-09-21
+ * # Updated for L2/19-083 by Andrew Glass 2019-05-06
+ * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
+ * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
+ * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * UnicodeData.txt does not have a header.
+ */
+
+#ifndef HB_OT_SHAPER_USE_TABLE_HH
+#define HB_OT_SHAPER_USE_TABLE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-use-machine.hh"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#define B USE(B) /* BASE */
+#define CGJ USE(CGJ) /* CGJ */
+#define CS USE(CS) /* CONS_WITH_STACKER */
+#define G USE(G) /* HIEROGLYPH */
+#define GB USE(GB) /* BASE_OTHER */
+#define H USE(H) /* HALANT */
+#define HN USE(HN) /* HALANT_NUM */
+#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */
+#define IS USE(IS) /* INVISIBLE_STACKER */
+#define J USE(J) /* HIEROGLYPH_JOINER */
+#define N USE(N) /* BASE_NUM */
+#define O USE(O) /* OTHER */
+#define R USE(R) /* REPHA */
+#define SB USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
+#define SE USE(SE) /* HIEROGLYPH_SEGMENT_END */
+#define SUB USE(SUB) /* CONS_SUB */
+#define Sk USE(Sk) /* SAKOT */
+#define WJ USE(WJ) /* Word_Joiner */
+#define ZWNJ USE(ZWNJ) /* ZWNJ */
+#define CMAbv USE(CMAbv)
+#define CMBlw USE(CMBlw)
+#define FAbv USE(FAbv)
+#define FBlw USE(FBlw)
+#define FPst USE(FPst)
+#define FMAbv USE(FMAbv)
+#define FMBlw USE(FMBlw)
+#define FMPst USE(FMPst)
+#define MAbv USE(MAbv)
+#define MBlw USE(MBlw)
+#define MPst USE(MPst)
+#define MPre USE(MPre)
+#define SMAbv USE(SMAbv)
+#define SMBlw USE(SMBlw)
+#define VAbv USE(VAbv)
+#define VBlw USE(VBlw)
+#define VPst USE(VPst)
+#define VPre USE(VPre)
+#define VMAbv USE(VMAbv)
+#define VMBlw USE(VMBlw)
+#define VMPst USE(VMPst)
+#define VMPre USE(VMPre)
+#pragma GCC diagnostic pop
+
+
+#ifndef HB_OPTIMIZE_SIZE
+
+static const uint8_t
+hb_use_u8[3141] =
+{
+ 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 14, 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 4, 2, 2,
+ 5, 6, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 17,
+ 18, 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 33, 2, 2, 2,
+ 2, 34, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 38, 39, 40, 41, 42, 43, 2, 44, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 46, 2,
+ 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2,
+ 2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69,
+ 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 80,
+ 2, 81, 81, 81, 81, 81, 81, 81, 81, 82, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 83, 84, 2, 2, 2, 2, 2, 2, 2, 85,
+ 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 81, 81, 81, 87, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
+ 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 2,
+ 2, 2, 2, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 95, 95, 96, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
+ 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
+ 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
+ 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
+ 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
+ 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
+ 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
+ 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
+ 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
+ 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
+ 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
+ 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
+ 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
+ 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
+ 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
+ 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
+ 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
+ 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
+ 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
+ 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
+ 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
+ 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
+ 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
+ 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
+ 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
+ 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
+ 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
+ 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
+ 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
+ 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
+ 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
+ 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
+ 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
+ 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
+ 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
+ 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
+ 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
+ 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
+ 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
+ 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
+ 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
+ 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
+ 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
+ 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
+ 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
+ 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
+ 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
+ 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
+ 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
+ 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
+ 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
+ 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
+ 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
+ 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
+ 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
+ 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
+ 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
+ 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
+ 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
+ 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
+ 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
+ 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
+ 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
+ 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
+ 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
+ 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
+ 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
+ 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
+ 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
+ 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
+ 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
+ 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
+ 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
+ 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
+ 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
+ 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
+ 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
+ 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
+ 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
+ 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
+ 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
+ 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
+ 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
+ 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
+ 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
+ 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
+ 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
+ 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
+ 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
+ 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
+ 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
+ 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
+ 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
+ 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
+ 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
+ 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
+ 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
+ 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
+ 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
+ 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
+ O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
+ CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
+ VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
+ VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
+ O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
+ VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
+ B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
+ SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
+ MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
+ VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
+ VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
+ B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
+ SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
+ SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
+ CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
+ VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
+ O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
+ VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
+ CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
+ R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
+ H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
+ MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
+ H, B,VMBlw, O, VBlw,
+};
+static const uint16_t
+hb_use_u16[784] =
+{
+ 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
+ 0, 0, 0, 0, 9, 12, 0, 0, 13, 9, 9, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 17, 25, 26, 20, 21, 27, 28, 29, 30, 31,
+ 32, 33, 21, 34, 35, 0, 17, 36, 37, 20, 21, 38, 23, 39, 17, 40,
+ 41, 42, 43, 44, 45, 46, 30, 0, 47, 48, 21, 49, 50, 51, 17, 0,
+ 52, 48, 21, 53, 50, 54, 17, 55, 56, 48, 9, 57, 58, 59, 17, 0,
+ 60, 61, 9, 62, 63, 64, 30, 65, 66, 67, 9, 68, 69, 9, 70, 71,
+ 72, 73, 74, 75, 76, 0, 0, 0, 9, 9, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 0, 0, 0, 0, 9, 85, 9, 86, 9, 87, 88, 89,
+ 9, 9, 9, 90, 91, 92, 2, 0, 93, 0, 9, 9, 9, 9, 9, 94,
+ 95, 9, 96, 0, 0, 0, 0, 0, 97, 98, 99,100, 30, 9,101,102,
+ 9, 9,103, 9,104,105, 0, 0, 9,106, 9, 9, 9,107,108,109,
+ 2, 2, 0, 0, 0, 0, 0, 0,110, 9, 9,111,112, 2,113,114,
+ 115, 9,116, 9, 9, 9,117,118, 9, 9,119,120,121, 0, 0, 0,
+ 0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125,
+ 126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132,
+ 0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 9, 9, 9,134,135,
+ 136, 9,137, 0, 9, 9, 9,138,139, 9, 9,140,141, 2,142,143,
+ 9, 9,144, 9,145,146, 0, 0,147, 9, 9,148,149, 2,150, 98,
+ 9, 9,151,152,153, 2, 9,154, 9, 9, 9,155,156, 0,157,158,
+ 0, 0, 0, 0, 9, 9,159, 2,160, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0,162,
+ 0, 0, 0, 0, 0, 0, 0,163,163,164, 33,165, 0, 0, 0, 0,
+ 166,167, 9,168, 94, 0, 0, 0, 0, 0, 0, 0, 69, 9,169, 0,
+ 9,170,171, 0, 0, 0, 0, 0, 9, 9,172, 2, 0, 0, 0, 0,
+ 9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9,
+ 176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184,
+ 185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192,
+ 185, 9, 9,193,194,105,195,102, 9, 33,196,197,198, 0, 0, 0,
+ 199,200, 94, 9, 9,201,202, 2,203, 20, 21,204,205,206,207,208,
+ 9, 9, 9,209,210,211,212, 0,195, 9, 9,213,214, 2, 0, 0,
+ 9, 9,215,216,217,218, 0, 0, 9, 9, 9,219,220, 2, 0, 0,
+ 9, 9,221,222, 2, 0, 0, 0, 9,223,224,103,225, 0, 0, 0,
+ 9, 9,226,227, 0, 0, 0, 0,228,229, 9,230,231, 2, 0, 0,
+ 0, 0,232, 9, 9,233,234, 0,235, 9, 9,236,237,238, 9, 9,
+ 239,240, 0, 0, 0, 0, 0, 0, 21, 9,215,241, 7, 9, 70, 18,
+ 9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
+ 248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
+ 251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9,254,255,256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 9, 9, 9,257, 0, 0, 0, 0, 9, 9, 9, 9,258,259,260,260,
+ 261,262, 0, 0, 0, 0,263, 0, 9, 9, 9, 9, 9,264, 0, 0,
+ 9, 9, 9, 9, 9, 9,105, 70, 94,265, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,266, 9, 9, 70,267,268, 0, 0, 0,
+ 0, 9,269, 0, 9, 9,270, 2, 0, 0, 0, 0, 0, 9,271, 2,
+ 9, 9, 9, 9,272, 2, 0, 0,129,129,129,129,129,129,129,129,
+ 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
+};
+
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+ return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+}
+
+
+#else
+
+static const uint8_t
+hb_use_u8[3413] =
+{
+ 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 14, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 1,
+ 11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19, 1,
+ 1, 20, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 22, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 24, 25, 26, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27,
+ 28, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 30, 31, 1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47, 48,
+ 49, 50, 50, 50, 50, 51, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 53, 1, 1, 1,
+ 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50, 55, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 56, 1, 1,
+ 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 58, 59, 1, 60, 1, 1, 1, 1, 61, 1, 1, 1, 1, 1,
+ 1, 62, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0,
+ 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 36, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 0, 55, 56, 57, 58, 59, 0, 0, 0, 60, 61, 62, 63, 55, 64, 65,
+ 66, 67, 55, 55, 68, 69, 70, 0, 0, 71, 72, 73, 74, 55, 75, 76,
+ 0, 77, 55, 78, 79, 80, 0, 0, 0, 81, 82, 83, 84, 85, 86, 55,
+ 87, 55, 88, 89, 0, 0, 0, 90, 91, 0, 0, 0, 0, 0, 0, 0,
+ 92, 93, 94, 0, 95, 96, 0, 0, 97, 0, 0, 0, 0, 0, 0, 98,
+ 0, 0, 99, 55, 100, 0, 0, 0, 0, 101, 102, 55, 103, 104, 105, 106,
+ 107, 55, 108, 109, 0, 110, 111, 112, 113, 55, 114, 115, 116, 55, 117, 118,
+ 119, 0, 0, 0, 0, 0, 0, 55, 120, 121, 0, 0, 0, 0, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 124, 125, 126, 0,
+ 0, 127, 128, 129, 0, 0, 0, 50, 130, 0, 0, 0, 0, 131, 132, 0,
+ 0, 55, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 134, 0,
+ 0, 0, 99, 135, 99, 136, 137, 138, 0, 139, 140, 141, 142, 143, 144, 145,
+ 0, 146, 147, 148, 149, 143, 150, 151, 152, 153, 154, 155, 0, 156, 157, 158,
+ 159, 160, 161, 162, 163, 0, 0, 0, 0, 55, 164, 165, 166, 167, 168, 169,
+ 0, 0, 0, 0, 0, 55, 170, 171, 0, 55, 172, 173, 0, 55, 174, 66,
+ 0, 175, 176, 177, 0, 0, 0, 0, 0, 55, 178, 0, 0, 0, 0, 0,
+ 0, 179, 180, 181, 0, 0, 182, 183, 184, 185, 186, 187, 55, 188, 0, 0,
+ 0, 189, 190, 191, 192, 193, 194, 0, 0, 195, 196, 197, 198, 199, 66, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 200, 201, 202, 203, 0, 0, 0, 0,
+ 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 204, 205, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 66, 0, 55, 206, 0, 0, 0, 0, 0,
+ 0, 55, 55, 207, 208, 209, 0, 0, 210, 55, 55, 55, 55, 55, 55, 211,
+ 0, 55, 55, 55, 212, 213, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0,
+ 0, 55, 215, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 217, 55,
+ 218, 0, 0, 0, 0, 0, 0, 99, 219, 55, 55, 220, 0, 0, 0, 0,
+ 0, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222,
+ 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
+ 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
+ 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
+ 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
+ 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
+ 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
+ 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
+ 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
+ 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
+ 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
+ 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
+ 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
+ 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
+ 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
+ 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
+ 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
+ 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
+ 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
+ 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
+ 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
+ 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
+ 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
+ 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
+ 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
+ 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
+ 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
+ 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
+ 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
+ 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
+ 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
+ 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
+ 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
+ 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
+ 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
+ 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
+ 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
+ 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
+ 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
+ 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
+ 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
+ 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
+ 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
+ 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
+ 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
+ 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
+ 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
+ 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
+ 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
+ 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
+ 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
+ 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
+ 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
+ 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
+ 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
+ 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
+ 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
+ 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
+ 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
+ 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
+ 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
+ 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
+ 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
+ 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
+ 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
+ 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
+ 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
+ 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
+ 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
+ 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
+ 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
+ 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
+ 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
+ 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
+ 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
+ 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
+ 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
+ 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
+ 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
+ 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
+ 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
+ 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
+ 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
+ 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
+ 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
+ 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
+ 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
+ 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
+ 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
+ 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
+ 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
+ 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
+ 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
+ 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
+ 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
+ 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
+ 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
+ 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
+ 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
+ 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
+ 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
+ O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
+ CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
+ VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
+ VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
+ O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
+ VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
+ B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
+ SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
+ MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
+ VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
+ VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
+ B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
+ SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
+ SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
+ CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
+ VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
+ O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
+ VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
+ CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
+ R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
+ H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
+ MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
+ H, B,VMBlw, O, VBlw,
+};
+static const uint16_t
+hb_use_u16[448] =
+{
+ 0, 0, 1, 2, 3, 4, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11,
+ 9, 12, 13, 9, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 17, 25, 26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35, 0,
+ 17, 36, 37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46,
+ 30, 0, 47, 48, 21, 49, 50, 51, 17, 0, 52, 48, 21, 53, 50, 54,
+ 17, 55, 56, 48, 9, 57, 58, 59, 60, 61, 9, 62, 63, 64, 30, 65,
+ 66, 67, 9, 68, 69, 9, 70, 71, 72, 73, 74, 75, 76, 0, 9, 9,
+ 77, 78, 79, 80, 81, 82, 83, 84, 9, 85, 9, 86, 9, 87, 88, 89,
+ 9, 90, 91, 92, 2, 0, 93, 0, 9, 94, 95, 9, 96, 0, 97, 98,
+ 99,100, 30, 9,101,102,103, 9,104,105, 9,106, 9,107,108,109,
+ 2, 2,110, 9, 9,111,112, 2,113,114,115, 9,116, 9,117,118,
+ 119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0,129,130,
+ 131, 0, 0,132,133, 0, 0, 9,134,135,136, 9,137, 0, 9,138,
+ 139, 9, 9,140,141, 2,142,143,144, 9,145,146,147, 9, 9,148,
+ 149, 2,150, 98,151,152,153, 2, 9,154, 9,155,156, 0,157,158,
+ 159, 2,160, 0, 0,161, 0,162, 0,163,163,164, 33,165,166,167,
+ 9,168, 94, 0,169, 0, 9,170,171, 0,172, 2,173,170,174,175,
+ 176, 0, 0,177,178, 0,179, 9, 9,180,181,182,183,184,185, 9,
+ 9,186,187, 0,188, 9,189,190,191, 9, 9,192, 9,193,194,105,
+ 195,102, 9, 33,196,197,198, 0,199,200, 94, 9, 9,201,202, 2,
+ 203, 20, 21,204,205,206,207,208, 9,209,210,211,212, 0,195, 9,
+ 9,213,214, 2,215,216,217,218, 9,219,220, 2,221,222, 9,223,
+ 224,103,225, 0,226,227,228,229, 9,230,231, 2,232, 9, 9,233,
+ 234, 0,235, 9, 9,236,237,238,239,240, 21, 9,215,241, 7, 9,
+ 70, 18, 9,242, 73,243,244, 9, 9,245,246, 2,247, 9,248,249,
+ 9,250,251, 48, 9,252,253, 2, 9,254,255,256, 9,257,258,259,
+ 260,260,261,262,263, 0, 9,264,105, 70, 94,265, 0,266, 70,267,
+ 268, 0,269, 0,270, 2,271, 2,272, 2,129,129,160,160,160,129,
+};
+
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+ return u<921600u?hb_use_u8[3049+(((hb_use_u8[865+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+}
+
+#endif
+
+#undef B
+#undef CGJ
+#undef CS
+#undef G
+#undef GB
+#undef H
+#undef HN
+#undef HVM
+#undef IS
+#undef J
+#undef N
+#undef O
+#undef R
+#undef SB
+#undef SE
+#undef SUB
+#undef Sk
+#undef WJ
+#undef ZWNJ
+#undef CMAbv
+#undef CMBlw
+#undef FAbv
+#undef FBlw
+#undef FPst
+#undef FMAbv
+#undef FMBlw
+#undef FMPst
+#undef MAbv
+#undef MBlw
+#undef MPst
+#undef MPre
+#undef SMAbv
+#undef SMBlw
+#undef VAbv
+#undef VBlw
+#undef VPst
+#undef VPre
+#undef VMAbv
+#undef VMBlw
+#undef VMPst
+#undef VMPre
+
+
+#endif /* HB_OT_SHAPER_USE_TABLE_HH */
+/* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shaper-use.cc
index 70b637933..342aba123 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/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"
/*
@@ -89,19 +89,19 @@ use_other_features[] =
HB_TAG('p','s','t','s'),
};
-static void
+static bool
setup_syllables_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_rphf_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
record_pref_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
-static void
+static bool
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -115,25 +115,25 @@ collect_features_use (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (setup_syllables_use);
/* "Default glyph pre-processing group" */
- map->enable_feature (HB_TAG('l','o','c','l'));
- map->enable_feature (HB_TAG('c','c','m','p'));
- map->enable_feature (HB_TAG('n','u','k','t'));
- map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+ map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
+ map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
+ map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
/* "Reordering group" */
map->add_gsub_pause (_hb_clear_substitution_flags);
- map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
+ map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_rphf_use);
map->add_gsub_pause (_hb_clear_substitution_flags);
- map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_pref_use);
/* "Orthographic unit shaping group" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
- map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
+ map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (reorder_use);
- map->add_gsub_pause (_hb_clear_syllables);
+ 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++)
@@ -257,7 +257,6 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
switch (syllable_type)
{
- case use_symbol_cluster:
case use_hieroglyph_cluster:
case use_non_cluster:
/* These don't join. Nothing to do. */
@@ -269,6 +268,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
case use_standard_cluster:
case use_number_joiner_terminated_cluster:
case use_numeral_cluster:
+ case use_symbol_cluster:
case use_broken_cluster:
bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
@@ -293,19 +293,21 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
}
}
-static void
+static bool
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);
setup_rphf_mask (plan, buffer);
setup_topographical_masks (plan, buffer);
+ return false;
}
-static void
+static bool
record_rphf_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -313,7 +315,7 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
hb_mask_t mask = use_plan->rphf_mask;
- if (!mask) return;
+ if (!mask) return false;
hb_glyph_info_t *info = buffer->info;
foreach_syllable (buffer, start, end)
@@ -326,9 +328,10 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
break;
}
}
+ return false;
}
-static void
+static bool
record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
@@ -345,12 +348,13 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
break;
}
}
+ return false;
}
static inline bool
is_halant_use (const hb_glyph_info_t &info)
{
- return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
+ return (info.use_category() == USE(H) || info.use_category() == USE(HVM) || info.use_category() == USE(IS)) &&
!_hb_glyph_info_ligated (&info);
}
@@ -363,6 +367,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
(FLAG (use_virama_terminated_cluster) |
FLAG (use_sakot_terminated_cluster) |
FLAG (use_standard_cluster) |
+ FLAG (use_symbol_cluster) |
FLAG (use_broken_cluster) |
0))))
return;
@@ -436,17 +441,19 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
}
}
-static void
+static bool
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
+ bool ret = false;
if (buffer->message (font, "start reordering USE"))
{
- hb_syllabic_insert_dotted_circles (font, buffer,
- use_broken_cluster,
- USE(B),
- USE(R));
+ if (hb_syllabic_insert_dotted_circles (font, buffer,
+ use_broken_cluster,
+ USE(B),
+ USE(R)))
+ ret = true;
foreach_syllable (buffer, start, end)
reorder_syllable_use (buffer, start, end);
@@ -455,6 +462,8 @@ reorder_use (const hb_ot_shape_plan_t *plan,
}
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
+
+ return ret;
}
@@ -480,7 +489,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 */
@@ -488,12 +497,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
data_destroy_use,
preprocess_text_use,
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
nullptr, /* decompose */
compose_use,
setup_masks_use,
- HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
+ HB_TAG_NONE, /* gpos_tag */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shaper-vowel-constraints.cc
index 045731dfb..e76b554b0 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/hb-ot-shaper-vowel-constraints.cc
@@ -10,15 +10,15 @@
* # Date: 2015-03-12, 21:17:00 GMT [AG]
* # Date: 2019-11-08, 23:22:00 GMT [AG]
*
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # Scripts-15.0.0.txt
+ * # Date: 2022-04-26, 23:15:02 GMT
*/
#include "hb.hh"
#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)
@@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
+ case HB_SCRIPT_KHOJKI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur ().codepoint)
+ {
+ case 0x11200u:
+ switch (buffer->cur (1).codepoint)
+ {
+ case 0x1122Cu: case 0x11231u: case 0x11233u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x11206u:
+ matched = 0x1122Cu == buffer->cur (1).codepoint;
+ break;
+ case 0x1122Cu:
+ switch (buffer->cur (1).codepoint)
+ {
+ case 0x11230u: case 0x11231u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x11240u:
+ matched = 0x1122Eu == buffer->cur (1).codepoint;
+ break;
+ }
+ (void) buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ break;
+
case HB_SCRIPT_KHUDAWADI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
@@ -435,7 +469,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
default:
break;
}
- buffer->swap_buffers ();
+ buffer->sync ();
}
diff --git a/src/hb-ot-shape-complex-vowel-constraints.hh b/src/hb-ot-shaper-vowel-constraints.hh
index d9082d4ea..5a7ee1b0f 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.hh
+++ b/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/src/hb-ot-shape-complex.hh b/src/hb-ot-shaper.hh
index 8012a9ae9..0207b2bbe 100644
--- a/src/hb-ot-shape-complex.hh
+++ b/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().
@@ -117,8 +117,6 @@ struct hb_ot_complex_shaper_t
hb_font_t *font);
- hb_ot_shape_normalization_mode_t normalization_preference;
-
/* decompose()
* Called during shape()'s normalization.
* May be NULL.
@@ -147,12 +145,6 @@ struct hb_ot_complex_shaper_t
hb_buffer_t *buffer,
hb_font_t *font);
- /* gpos_tag()
- * If not HB_TAG_NONE, then must match found GPOS script tag for
- * GPOS to be applied. Otherwise, fallback positioning will be used.
- */
- hb_tag_t gpos_tag;
-
/* reorder_marks()
* Called during shape().
* Shapers can use to modify ordering of combining marks.
@@ -163,23 +155,31 @@ struct hb_ot_complex_shaper_t
unsigned int start,
unsigned int end);
+ /* gpos_tag()
+ * If not HB_TAG_NONE, then must match found GPOS script tag for
+ * GPOS to be applied. Otherwise, fallback positioning will be used.
+ */
+ hb_tag_t gpos_tag;
+
+ hb_ot_shape_normalization_mode_t normalization_preference;
+
hb_ot_shape_zero_width_marks_type_t zero_width_marks;
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,18 @@ 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;
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#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;
+#endif
/* Unicode-2.0 additions */
@@ -277,7 +276,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:
@@ -383,6 +382,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_TOTO:
case HB_SCRIPT_VITHKUQI:
+ /* Unicode-15.0 additions */
+ case HB_SCRIPT_KAWI:
+ case HB_SCRIPT_NAG_MUNDARI:
+
/* 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.
@@ -390,11 +393,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/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index 41d1734b3..59bb2dacc 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -57,6 +57,31 @@ enum
// Reserved = 0xFFFC /* Reserved for future use — set to zero. */
};
+struct StatAxisRecord
+{
+ int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+ hb_ot_name_id_t get_name_id () const { return nameID; }
+
+ hb_tag_t get_axis_tag () const { return tag; }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (likely (c->check_struct (this)));
+ }
+
+ protected:
+ Tag tag; /* A tag identifying the axis of design variation. */
+ NameID nameID; /* The name ID for entries in the 'name' table that
+ * provide a display string for this axis. */
+ HBUINT16 ordering; /* A value that applications can use to determine
+ * primary sorting of face names, or for ordering
+ * of descriptors when composing family or face names. */
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
struct AxisValueFormat1
{
unsigned int get_axis_index () const { return axisIndex; }
@@ -64,10 +89,41 @@ struct AxisValueFormat1
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+ hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ unsigned axis_idx = get_axis_index ();
+ return axis_records[axis_idx].get_axis_tag ();
+ }
+
+ bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+ const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ {
+ hb_tag_t axis_tag = get_axis_tag (axis_records);
+ float axis_value = get_value ();
+
+ if (!user_axes_location->has (axis_tag) ||
+ fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+ return true;
+
+ return false;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ TRACE_SUBSET (this);
+ const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location;
+
+ if (keep_axis_value (axis_records, user_axes_location))
+ return_trace (c->serializer->embed (this));
+
+ return_trace (false);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -80,7 +136,7 @@ struct AxisValueFormat1
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed value; /* A numeric value for this attribute value. */
+ F16DOT16 value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (12);
};
@@ -92,10 +148,41 @@ struct AxisValueFormat2
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+ hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ unsigned axis_idx = get_axis_index ();
+ return axis_records[axis_idx].get_axis_tag ();
+ }
+
+ bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+ const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ {
+ hb_tag_t axis_tag = get_axis_tag (axis_records);
+ float axis_value = get_value ();
+
+ if (!user_axes_location->has (axis_tag) ||
+ fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+ return true;
+
+ return false;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ TRACE_SUBSET (this);
+ const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location;
+
+ if (keep_axis_value (axis_records, user_axes_location))
+ return_trace (c->serializer->embed (this));
+
+ return_trace (false);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -108,10 +195,10 @@ struct AxisValueFormat2
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed nominalValue; /* A numeric value for this attribute value. */
- HBFixed rangeMinValue; /* The minimum value for a range associated
+ F16DOT16 nominalValue; /* A numeric value for this attribute value. */
+ F16DOT16 rangeMinValue; /* The minimum value for a range associated
* with the specified name ID. */
- HBFixed rangeMaxValue; /* The maximum value for a range associated
+ F16DOT16 rangeMaxValue; /* The maximum value for a range associated
* with the specified name ID. */
public:
DEFINE_SIZE_STATIC (20);
@@ -124,10 +211,41 @@ struct AxisValueFormat3
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+ hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ unsigned axis_idx = get_axis_index ();
+ return axis_records[axis_idx].get_axis_tag ();
+ }
+
+ bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+ const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ {
+ hb_tag_t axis_tag = get_axis_tag (axis_records);
+ float axis_value = get_value ();
+
+ if (!user_axes_location->has (axis_tag) ||
+ fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+ return true;
+
+ return false;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ TRACE_SUBSET (this);
+ const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location;
+
+ if (keep_axis_value (axis_records, user_axes_location))
+ return_trace (c->serializer->embed (this));
+
+ return_trace (false);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
@@ -140,8 +258,8 @@ struct AxisValueFormat3
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed value; /* A numeric value for this attribute value. */
- HBFixed linkedValue; /* The numeric value for a style-linked mapping
+ F16DOT16 value; /* A numeric value for this attribute value. */
+ F16DOT16 linkedValue; /* The numeric value for a style-linked mapping
* from this value. */
public:
DEFINE_SIZE_STATIC (16);
@@ -155,14 +273,14 @@ struct AxisValueRecord
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this));
}
protected:
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis to which this value
* applies. Must be less than designAxisCount. */
- HBFixed value; /* A numeric value for this attribute value. */
+ F16DOT16 value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (6);
};
@@ -172,12 +290,47 @@ struct AxisValueFormat4
const AxisValueRecord &get_axis_record (unsigned int axis_index) const
{ return axisValues.as_array (axisCount)[axis_index]; }
+ bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+ const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ {
+ hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
+
+ for (const auto& rec : axis_value_records)
+ {
+ unsigned axis_idx = rec.get_axis_index ();
+ float axis_value = rec.get_value ();
+ hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
+
+ if (user_axes_location->has (axis_tag) &&
+ fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f)
+ return false;
+ }
+
+ return true;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ TRACE_SUBSET (this);
+ const hb_hashmap_t<hb_tag_t, float> *user_axes_location = c->plan->user_axes_location;
+ if (!keep_axis_value (axis_records, user_axes_location))
+ return_trace (false);
+
+ unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
+ auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
+ if (unlikely (!out)) return_trace (false);
+ hb_memcpy (out, this, total_size);
+ return_trace (true);
+ }
+
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (likely (c->check_struct (this) &&
+ axisValues.sanitize (c, axisCount)));
}
protected:
@@ -234,6 +387,33 @@ struct AxisValue
}
}
+ 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)...));
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
+ bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+ hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
+ case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
+ case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
+ case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
+ default:return false;
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -263,27 +443,35 @@ struct AxisValue
DEFINE_SIZE_UNION (2, format);
};
-struct StatAxisRecord
+struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
{
- int cmp (hb_tag_t key) const { return tag.cmp (key); }
+ bool subset (hb_subset_context_t *c,
+ unsigned axisValueCount,
+ unsigned& count,
+ const hb_array_t<const StatAxisRecord> axis_records) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!out)) return_trace (false);
- hb_ot_name_id_t get_name_id () const { return nameID; }
+ auto axisValueOffsets = as_array (axisValueCount);
+ count = 0;
+ for (const auto& offset : axisValueOffsets)
+ {
+ if (!offset) continue;
+ auto o_snap = c->serializer->snapshot ();
+ auto *o = c->serializer->embed (offset);
+ if (!o) return_trace (false);
+ if (!o->serialize_subset (c, offset, this, axis_records))
+ {
+ c->serializer->revert (o_snap);
+ continue;
+ }
+ count++;
+ }
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
+ return_trace (count);
}
-
- protected:
- Tag tag; /* A tag identifying the axis of design variation. */
- NameID nameID; /* The name ID for entries in the 'name' table that
- * provide a display string for this axis. */
- HBUINT16 ordering; /* A value that applications can use to determine
- * primary sorting of face names, or for ordering
- * of descriptors when composing family or face names. */
- public:
- DEFINE_SIZE_STATIC (8);
};
struct STAT
@@ -329,7 +517,8 @@ struct STAT
return axis_value.get_value_name_id ();
}
- void collect_name_ids (hb_set_t *nameids_to_retain) const
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ hb_set_t *nameids_to_retain /* OUT */) const
{
if (!has_data ()) return;
@@ -338,13 +527,38 @@ struct STAT
| hb_sink (nameids_to_retain)
;
+ auto designAxes = get_design_axes ();
+
+ get_axis_value_offsets ()
| hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+ | hb_filter ([&] (const AxisValue& _)
+ { return _.keep_axis_value (designAxes, user_axes_location); })
| hb_map (&AxisValue::get_value_name_id)
| hb_sink (nameids_to_retain)
;
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ STAT *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ auto designAxes = get_design_axes ();
+ for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
+ if (unlikely (!c->serializer->embed (designAxes[i])))
+ return_trace (false);
+
+ if (designAxisCount)
+ c->serializer->check_assign (out->designAxesOffset, this->get_size (),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+ unsigned count = 0;
+ out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
+ axisValueCount, count, designAxes);
+ return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -381,7 +595,7 @@ struct STAT
* set to zero; if designAxisCount is greater
* than zero, must be greater than zero. */
HBUINT16 axisValueCount; /* The number of axis value tables. */
- NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
+ NNOffset32To<AxisValueOffsetArray>
offsetToAxisValueOffsets;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design
diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh
index fc9bffc23..9394b90ee 100644
--- a/src/hb-ot-tag-table.hh
+++ b/src/hb-ot-tag-table.hh
@@ -6,1607 +6,1624 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2021-09-02 09:40 PM" />
- * File-Date: 2021-08-06
+ * <meta name="updated_at" content="2022-01-28 10:00 PM" />
+ * File-Date: 2022-03-02
*/
#ifndef HB_OT_TAG_TABLE_HH
#define HB_OT_TAG_TABLE_HH
-static const LangTag ot_languages[] = {
- {"aa", HB_TAG('A','F','R',' ')}, /* Afar */
- {"aae", HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */
- {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */
- {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */
- {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */
- {"aba", HB_TAG_NONE }, /* Abé != Abaza */
- {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */
- {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */
- {"abs", HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */
- {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */
- {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */
- {"acf", HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */
-/*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */
- {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */
- {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */
- {"acr", HB_TAG('A','C','R',' ')}, /* Achi */
- {"acr", HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */
- {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */
- {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */
- {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */
- {"ada", HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */
- {"adf", HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */
- {"adp", HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */
-/*{"ady", HB_TAG('A','D','Y',' ')},*/ /* Adyghe */
- {"aeb", HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */
- {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */
- {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
- {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */
- {"afk", HB_TAG_NONE }, /* Nanubae != Afrikaans */
- {"afs", HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */
- {"agu", HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */
- {"agw", HB_TAG_NONE }, /* Kahua != Agaw */
- {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */
- {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */
- {"aig", HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */
- {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
- {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */
-/*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */
- {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */
- {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */
- {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */
- {"akb", HB_TAG('A','K','B',' ')}, /* Batak Angkola */
- {"akb", HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */
- {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */
- {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */
-/*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */
- {"am", HB_TAG('A','M','H',' ')}, /* Amharic */
- {"amf", HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */
- {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */
- {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */
-/*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */
- {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */
- {"apa", HB_TAG('A','T','H',' ')}, /* Apache [family] -> Athapaskan */
- {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */
- {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */
- {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */
- {"apk", HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */
- {"apl", HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */
- {"apm", HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */
- {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */
- {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
- {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */
- {"ari", HB_TAG_NONE }, /* Arikara != Aari */
- {"ark", HB_TAG_NONE }, /* Arikapú != Rakhine */
- {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */
- {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */
- {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */
- {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */
- {"ary", HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */
- {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */
- {"as", HB_TAG('A','S','M',' ')}, /* Assamese */
-/*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */
-/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [family] -> Athapaskan */
- {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */
- {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */
- {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */
- {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */
- {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */
- {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */
-/*{"avn", HB_TAG('A','V','N',' ')},*/ /* Avatime */
-/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */
- {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
- {"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */
- {"ayh", HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */
- {"ayl", HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */
- {"ayn", HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */
- {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */
- {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */
- {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */
- {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */
- {"azb", HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */
- {"azd", HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */
- {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */
- {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */
- {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */
- {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */
- {"bad", HB_TAG('B','A','D','0')}, /* Banda [family] */
- {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */
- {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */
- {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */
- {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */
-/*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */
-/*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */
- {"bau", HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */
- {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */
- {"bbc", HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */
- {"bbj", HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */
- {"bbp", HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */
- {"bbr", HB_TAG_NONE }, /* Girawa != Berber */
- {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */
- {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */
- {"bch", HB_TAG_NONE }, /* Bariai != Bench */
- {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */
- {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */
- {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
- {"bcr", HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */
-/*{"bdy", HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */
- {"be", HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */
- {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */
- {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */
-/*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */
- {"ber", HB_TAG('B','B','R',' ')}, /* Berber [family] */
- {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */
- {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */
- {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
- {"bft", HB_TAG('B','L','T',' ')}, /* Balti */
- {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */
- {"bfy", HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */
- {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
-/*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */
- {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */
- {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */
- {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */
- {"bgq", HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */
- {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */
- {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
-/*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */
- {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */
-/*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */
- {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */
- {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */
- {"bi", HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
-/*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */
- {"bil", HB_TAG_NONE }, /* Bile != Bilen */
- {"bin", HB_TAG('E','D','O',' ')}, /* Edo */
- {"biu", HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */
-/*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */
- {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */
- {"bjo", HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */
- {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
- {"bjs", HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */
- {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */
- {"bkf", HB_TAG_NONE }, /* Beeke != Blackfoot */
- {"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */
- {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */
- {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */
- {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */
- {"bli", HB_TAG_NONE }, /* Bolia != Baluchi */
- {"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */
- {"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */
- {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */
- {"blt", HB_TAG_NONE }, /* Tai Dam != Balti */
- {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */
- {"bmb", HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */
- {"bml", HB_TAG_NONE }, /* Bomboli != Bamileke */
- {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */
- {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */
- {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */
- {"bpd", HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */
- {"bpl", HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */
- {"bpq", HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */
-/*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */
- {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */
- {"bqk", HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */
- {"br", HB_TAG('B','R','E',' ')}, /* Breton */
- {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */
- {"brc", HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */
-/*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */
- {"bri", HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */
- {"brm", HB_TAG_NONE }, /* Barambu != Burmese */
-/*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */
- {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */
- {"bsh", HB_TAG_NONE }, /* Kati != Bashkir */
-/*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */
- {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */
- {"btd", HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */
- {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */
- {"bti", HB_TAG_NONE }, /* Burate != Beti */
- {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */
-/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [family] */
- {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */
- {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */
- {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */
- {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */
- {"bts", HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */
- {"btx", HB_TAG('B','T','X',' ')}, /* Batak Karo */
- {"btx", HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */
- {"btz", HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */
- {"btz", HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */
-/*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */
- {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */
- {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */
- {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */
- {"bwe", HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */
- {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */
- {"bxo", HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */
- {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */
- {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */
- {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */
- {"byv", HB_TAG('B','Y','V',' ')}, /* Medumba */
- {"byv", HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */
- {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */
- {"bzj", HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */
- {"bzk", HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */
- {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
- {"caa", HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */
- {"cac", HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */
- {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */
- {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */
- {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */
- {"cak", HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */
- {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */
- {"cbk", HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */
- {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */
- {"ccl", HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */
- {"ccm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */
- {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */
- {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */
- {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */
- {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
-/*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */
- {"cek", HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */
- {"cey", HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */
- {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */
- {"cfm", HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */
-/*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */
- {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
- {"chf", HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */
- {"chg", HB_TAG_NONE }, /* Chagatai != Chaha Gurage */
- {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */
- {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */
- {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */
- {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */
-/*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */
- {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
- {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */
- {"chp", HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */
- {"chq", HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */
-/*{"chr", HB_TAG('C','H','R',' ')},*/ /* Cherokee */
-/*{"chy", HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */
- {"chz", HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */
- {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */
-/*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */
-/*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */
- {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */
- {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */
- {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */
- {"ckn", HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */
- {"cks", HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */
- {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */
- {"ckz", HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */
- {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */
- {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */
- {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */
- {"clj", HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */
- {"clt", HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */
- {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */
- {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */
- {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */
- {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */
- {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */
- {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */
- {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */
- {"cnr", HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */
- {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */
- {"cnu", HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */
- {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */
- {"co", HB_TAG('C','O','S',' ')}, /* Corsican */
- {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */
- {"cob", HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */
-/*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */
- {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */
- {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */
- {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [family] -> Creoles */
- {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [family] -> Creoles */
- {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */
-/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [family] -> Creoles */
- {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */
- {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */
- {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */
- {"cqu", HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */
- {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */
- {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */
- {"cri", HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */
- {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */
- {"crj", HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */
- {"crj", HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */
- {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */
- {"crk", HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */
- {"crk", HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */
- {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */
- {"crl", HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */
- {"crl", HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */
- {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */
- {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */
- {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */
- {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [family] -> Creoles */
- {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */
- {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */
- {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */
- {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
- {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */
- {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
- {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */
-/*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */
- {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */
- {"csj", HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */
- {"csl", HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */
- {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */
- {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */
- {"csv", HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */
- {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */
- {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */
- {"csw", HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */
- {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */
- {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */
- {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */
- {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */
-/*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */
- {"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */
- {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */
- {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */
-/*{"ctt", HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */
- {"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */
- {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */
- {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */
-/*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */
- {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
- {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */
- {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
- {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */
- {"cwd", HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */
- {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
- {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */
- {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */
- {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */
- {"da", HB_TAG('D','A','N',' ')}, /* Danish */
-/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */
- {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */
- {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */
-/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */
-/*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */
- {"dcr", HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */
- {"de", HB_TAG('D','E','U',' ')}, /* German */
- {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */
- {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
- {"dep", HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */
- {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */
- {"dgo", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */
- {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */
- {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */
-/*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */
- {"dhv", HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */
- {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */
- {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */
- {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */
- {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */
- {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */
- {"diq", HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */
- {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */
- {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */
- {"djk", HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */
- {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */
- {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */
- {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
-/*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */
- {"dnk", HB_TAG_NONE }, /* Dengka != Dinka */
- {"doi", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */
- {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */
- {"dri", HB_TAG_NONE }, /* C'Lela != Dari */
- {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */
- {"drw", HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */
- {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
- {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */
-/*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */
- {"dun", HB_TAG_NONE }, /* Dusun Deyah != Dungan */
- {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */
- {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */
- {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */
- {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */
- {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */
- {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */
- {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */
- {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */
- {"dzn", HB_TAG_NONE }, /* Dzando != Dzongkha */
- {"ecr", HB_TAG_NONE }, /* Eteocretan != Eastern Cree */
- {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */
-/*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */
- {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */
- {"eky", HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */
- {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */
- {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */
- {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */
- {"emy", HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */
- {"en", HB_TAG('E','N','G',' ')}, /* English */
- {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */
- {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets */
- {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets */
- {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */
- {"es", HB_TAG('E','S','P',' ')}, /* Spanish */
- {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */
- {"esi", HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */
- {"esk", HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */
-/*{"esu", HB_TAG('E','S','U',' ')},*/ /* Central Yupik */
- {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */
- {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */
- {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */
- {"euq", HB_TAG_NONE }, /* Basque [family] != Basque */
- {"eve", HB_TAG('E','V','N',' ')}, /* Even */
- {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */
- {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */
- {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */
- {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */
- {"fab", HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */
- {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */
- {"fan", HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */
- {"far", HB_TAG_NONE }, /* Fataleka != Persian */
- {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */
- {"fat", HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */
- {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */
- {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */
- {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */
- {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
- {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
- {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
- {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */
- {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */
- {"fmp", HB_TAG('F','M','P',' ')}, /* Fe’fe’ */
- {"fmp", HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */
- {"fng", HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */
- {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
-/*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */
- {"fos", HB_TAG_NONE }, /* Siraya != Faroese */
- {"fpe", HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */
- {"fr", HB_TAG('F','R','A',' ')}, /* French */
-/*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */
-/*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */
- {"fub", HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */
- {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */
- {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */
- {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */
- {"fuf", HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */
- {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */
- {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */
- {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */
- {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */
- {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */
- {"fuv", HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */
- {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
- {"ga", HB_TAG('I','R','I',' ')}, /* Irish */
- {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */
- {"gac", HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */
- {"gad", HB_TAG_NONE }, /* Gaddang != Ga */
- {"gae", HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */
-/*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */
- {"gal", HB_TAG_NONE }, /* Galolen != Galician */
- {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */
- {"gar", HB_TAG_NONE }, /* Galeya != Garshuni */
- {"gaw", HB_TAG_NONE }, /* Nobonob != Garhwali */
- {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */
- {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */
- {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */
- {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */
- {"gcf", HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */
- {"gcl", HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */
- {"gcr", HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */
- {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */
- {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */
-/*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */
- {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */
- {"gha", HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */
- {"ghk", HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */
- {"gho", HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */
- {"gib", HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */
-/*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */
- {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */
- {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */
- {"gkp", HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */
- {"gkp", HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */
- {"gl", HB_TAG('G','A','L',' ')}, /* Galician */
- {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
-/*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */
- {"gmz", HB_TAG_NONE }, /* Mgbolizhia != Gumuz */
- {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
- {"gnb", HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */
-/*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */
- {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */
- {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */
-/*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */
- {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */
-/*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */
- {"goq", HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */
- {"gox", HB_TAG('B','A','D','0')}, /* Gobu -> Banda */
- {"gpe", HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */
- {"gro", HB_TAG_NONE }, /* Groma != Garo */
- {"grr", HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */
- {"grt", HB_TAG('G','R','O',' ')}, /* Garo */
- {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */
- {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */
- {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
- {"gua", HB_TAG_NONE }, /* Shiki != Guarani */
-/*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */
-/*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */
- {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */
- {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */
- {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
- {"gul", HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */
- {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */
-/*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */
- {"gv", HB_TAG('M','N','X',' ')}, /* Manx */
- {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */
- {"gyn", HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */
- {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
- {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */
- {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */
- {"hai", HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */
- {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */
- {"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */
- {"har", HB_TAG('H','R','I',' ')}, /* Harari */
-/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */
- {"hax", HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */
-/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */
-/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */
- {"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */
- {"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */
- {"hdn", HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */
- {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
- {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */
-/*{"hei", HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */
- {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
-/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */
- {"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */
- {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */
- {"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */
- {"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */
- {"hmd", HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */
- {"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */
- {"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */
- {"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */
- {"hmh", HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */
- {"hmi", HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */
- {"hmj", HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */
- {"hml", HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */
- {"hmm", HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */
-/*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */
- {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */
- {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */
- {"hmr", HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */
- {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */
- {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */
- {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */
- {"hmz", HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */
- {"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */
-/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */
- {"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */
- {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */
- {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */
- {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */
- {"ho", HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */
- {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */
- {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */
- {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */
- {"hoj", HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */
- {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */
- {"hra", HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */
- {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */
- {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */
- {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */
- {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */
- {"ht", HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */
- {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */
- {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */
- {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */
- {"hus", HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */
- {"hwc", HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */
- {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */
- {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */
- {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */
- {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
- {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */
-/*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */
-/*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */
- {"iby", HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */
- {"icr", HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */
- {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */
- {"id", HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */
- {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */
- {"idb", HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */
- {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */
- {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */
- {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */
- {"ihb", HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */
- {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */
- {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */
- {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */
- {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */
-/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [family] */
- {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */
- {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */
- {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */
- {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */
-/*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */
- {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */
- {"in", HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */
- {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */
- {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
- {"io", HB_TAG('I','D','O',' ')}, /* Ido */
- {"iri", HB_TAG_NONE }, /* Rigwe != Irish */
-/*{"iru", HB_TAG('I','R','U',' ')},*/ /* Irula */
- {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
- {"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */
- {"it", HB_TAG('I','T','A',' ')}, /* Italian */
- {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */
- {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */
- {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */
- {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */
- {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */
- {"jac", HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */
- {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */
- {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */
- {"jam", HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */
- {"jan", HB_TAG_NONE }, /* Jandai != Japanese */
- {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */
- {"jbe", HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */
- {"jbn", HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */
-/*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */
-/*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */
- {"jgo", HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */
- {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */
- {"jii", HB_TAG_NONE }, /* Jiiddu != Yiddish */
- {"jkm", HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */
- {"jkp", HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */
- {"jud", HB_TAG_NONE }, /* Worodougou != Ladino */
- {"jul", HB_TAG_NONE }, /* Jirel != Jula */
- {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */
- {"jvd", HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */
- {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */
- {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */
- {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */
- {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */
- {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */
- {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */
- {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
- {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
-/*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */
- {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
- {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */
- {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */
- {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */
- {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */
- {"kcn", HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */
-/*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */
- {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */
- {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */
- {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */
- {"kea", HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */
- {"keb", HB_TAG_NONE }, /* Kélé != Kebena */
- {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */
- {"kek", HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */
- {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */
- {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */
- {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */
- {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */
- {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */
- {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */
- {"kge", HB_TAG_NONE }, /* Komering != Khutsuri Georgian */
- {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */
- {"khb", HB_TAG('X','B','D',' ')}, /* Lü */
- {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */
- {"khn", HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */
- {"khs", HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */
- {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */
- {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */
- {"khv", HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */
-/*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */
- {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */
- {"kis", HB_TAG_NONE }, /* Kis != Kisii */
- {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */
- {"kiu", HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */
- {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */
- {"kjb", HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */
-/*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */
- {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */
- {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */
- {"kjp", HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */
- {"kjt", HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */
-/*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */
- {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */
- {"kkn", HB_TAG_NONE }, /* Kon Keu != Kokni */
- {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */
- {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */
- {"klm", HB_TAG_NONE }, /* Migum != Kalmyk */
- {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */
- {"km", HB_TAG('K','H','M',' ')}, /* Khmer */
- {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */
- {"kmn", HB_TAG_NONE }, /* Awtuw != Kumaoni */
- {"kmo", HB_TAG_NONE }, /* Kwoma != Komo */
- {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */
- {"kms", HB_TAG_NONE }, /* Kamasau != Komso */
- {"kmv", HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */
- {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */
-/*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */
- {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */
- {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */
- {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */
- {"knj", HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */
- {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */
- {"knr", HB_TAG_NONE }, /* Kaningra != Kanuri */
- {"ko", HB_TAG('K','O','R',' ')}, /* Korean */
- {"ko", HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */
- {"kod", HB_TAG_NONE }, /* Kodi != Kodagu */
- {"koh", HB_TAG_NONE }, /* Koyo != Korean Old Hangul */
- {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */
- {"koi", HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */
-/*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */
- {"kop", HB_TAG_NONE }, /* Waube != Komi-Permyak */
-/*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */
- {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */
- {"koz", HB_TAG_NONE }, /* Korak != Komi-Zyrian */
- {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */
- {"kpl", HB_TAG_NONE }, /* Kpala != Kpelle */
- {"kpp", HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */
- {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */
- {"kpv", HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */
- {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */
- {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */
- {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */
- {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */
- {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */
- {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */
- {"kri", HB_TAG('K','R','I',' ')}, /* Krio */
- {"kri", HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */
- {"krk", HB_TAG_NONE }, /* Kerek != Karakalpak */
-/*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */
- {"krm", HB_TAG_NONE }, /* Krim (retired code) != Karaim */
- {"krn", HB_TAG_NONE }, /* Sapo != Karen */
- {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */
- {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */
- {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */
- {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */
- {"ksi", HB_TAG_NONE }, /* Krisa != Khasi */
- {"ksm", HB_TAG_NONE }, /* Kumba != Kildin Sami */
- {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */
- {"ksw", HB_TAG('K','S','W',' ')}, /* S’gaw Karen */
- {"ksw", HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */
- {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */
- {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */
- {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */
- {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */
- {"kui", HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */
- {"kul", HB_TAG_NONE }, /* Kulere != Kulvi */
-/*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */
- {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */
- {"kuw", HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */
- {"kuy", HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */
- {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */
- {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */
- {"kvl", HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */
- {"kvq", HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */
- {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */
- {"kvt", HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */
- {"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */
- {"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */
- {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */
-/*{"kwk", HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */
- {"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */
- {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */
- {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */
- {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */
- {"kxf", HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */
- {"kxk", HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */
- {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */
- {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */
- {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */
- {"kyk", HB_TAG_NONE }, /* Kamayo != Koryak */
- {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */
- {"kyu", HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */
- {"la", HB_TAG('L','A','T',' ')}, /* Latin */
- {"lac", HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */
- {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */
- {"lah", HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */
- {"lak", HB_TAG_NONE }, /* Laka (Nigeria) != Lak */
- {"lam", HB_TAG_NONE }, /* Lamba != Lambani */
- {"laz", HB_TAG_NONE }, /* Aribwatsa != Laz */
- {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */
- {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */
- {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */
- {"lbl", HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */
- {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */
- {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */
- {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */
- {"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */
-/*{"lef", HB_TAG('L','E','F',' ')},*/ /* Lelemi */
-/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */
- {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */
- {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */
- {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */
-/*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */
- {"lir", HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */
-/*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */
- {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */
- {"liy", HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */
-/*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */
- {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */
-/*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */
- {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */
- {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */
- {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */
- {"lma", HB_TAG_NONE }, /* East Limba != Low Mari */
- {"lmb", HB_TAG_NONE }, /* Merei != Limbu */
- {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */
-/*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */
- {"lmw", HB_TAG_NONE }, /* Lake Miwok != Lomwe */
- {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */
- {"lna", HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */
- {"lnl", HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */
- {"lo", HB_TAG('L','A','O',' ')}, /* Lao */
-/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */
- {"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */
-/*{"lpo", HB_TAG('L','P','O',' ')},*/ /* Lipo */
-/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */
- {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */
- {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */
- {"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */
- {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */
- {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */
- {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
- {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */
- {"lth", HB_TAG_NONE }, /* Thur != Lithuanian */
- {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */
- {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */
- {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */
-/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */
-/*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */
- {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */
- {"lus", HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */
- {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */
- {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */
- {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */
- {"lvi", HB_TAG_NONE }, /* Lavi != Latvian */
- {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */
- {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */
- {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */
- {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */
-/*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */
-/*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */
- {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */
- {"maj", HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */
- {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */
- {"mam", HB_TAG('M','A','M',' ')}, /* Mam */
- {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */
- {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */
- {"map", HB_TAG_NONE }, /* Austronesian [family] != Mapudungun */
- {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */
- {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */
- {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */
- {"mbf", HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */
- {"mbn", HB_TAG_NONE }, /* Macaguán != Mbundu */
-/*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */
- {"mch", HB_TAG_NONE }, /* Maquiritari != Manchu */
- {"mcm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */
- {"mcr", HB_TAG_NONE }, /* Menya != Moose Cree */
- {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */
- {"mde", HB_TAG_NONE }, /* Maba (Chad) != Mende */
- {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */
-/*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */
- {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */
- {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */
- {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */
-/*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */
- {"mfa", HB_TAG('M','F','A',' ')}, /* Pattani Malay */
- {"mfa", HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */
- {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */
- {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */
- {"mfe", HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */
- {"mfp", HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */
- {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */
- {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */
- {"mhc", HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */
- {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */
- {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */
- {"mi", HB_TAG('M','R','I',' ')}, /* Maori */
- {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */
- {"min", HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */
- {"miz", HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */
- {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */
- {"mkn", HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */
- {"mkr", HB_TAG_NONE }, /* Malas != Makasar */
- {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */
-/*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */
- {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
- {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
- {"mle", HB_TAG_NONE }, /* Manambu != Male */
- {"mln", HB_TAG_NONE }, /* Malango != Malinke */
- {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */
- {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */
- {"mlr", HB_TAG_NONE }, /* Vame != Malayalam Reformed */
- {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */
- {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
- {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */
- {"mnd", HB_TAG_NONE }, /* Mondé != Mandinka */
- {"mng", HB_TAG_NONE }, /* Eastern Mnong != Mongolian */
- {"mnh", HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */
-/*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */
- {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */
- {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */
- {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */
- {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */
- {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */
- {"mnx", HB_TAG_NONE }, /* Manikion != Manx */
- {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
- {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */
-/*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */
- {"mok", HB_TAG_NONE }, /* Morori != Moksha */
- {"mop", HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */
- {"mor", HB_TAG_NONE }, /* Moro != Moroccan */
-/*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */
- {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
- {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */
- {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
- {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */
- {"mrj", HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */
- {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
- {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */
- {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */
- {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */
- {"msi", HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */
- {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */
- {"mth", HB_TAG_NONE }, /* Munggui != Maithili */
- {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */
- {"mts", HB_TAG_NONE }, /* Yora != Maltese */
- {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */
- {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */
- {"mun", HB_TAG_NONE }, /* Munda [family] != Mundari */
- {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */
- {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */
-/*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */
- {"mvb", HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */
- {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */
- {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */
- {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */
-/*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */
- {"mwq", HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */
- {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */
- {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */
- {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */
- {"my", HB_TAG('B','R','M',' ')}, /* Burmese */
- {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */
-/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [family] */
- {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */
- {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */
- {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */
-/*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */
- {"mzs", HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */
- {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */
- {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */
- {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */
-/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [family] */
- {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */
-/*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */
- {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */
- {"naz", HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */
- {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */
- {"nch", HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */
- {"nci", HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */
- {"ncj", HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */
- {"ncl", HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */
- {"ncr", HB_TAG_NONE }, /* Ncane != N-Cree */
- {"ncx", HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */
- {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */
- {"ndb", HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */
-/*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */
- {"ndg", HB_TAG_NONE }, /* Ndengereko != Ndonga */
-/*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */
- {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */
- {"nef", HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */
-/*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */
- {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */
-/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */
- {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
- {"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */
- {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */
- {"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */
- {"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */
- {"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */
- {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */
- {"nhe", HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */
- {"nhg", HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */
- {"nhi", HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */
- {"nhk", HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */
- {"nhm", HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */
- {"nhn", HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */
- {"nhp", HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */
- {"nhq", HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */
- {"nht", HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */
- {"nhv", HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */
- {"nhw", HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */
- {"nhx", HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */
- {"nhy", HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */
- {"nhz", HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */
- {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */
- {"nis", HB_TAG_NONE }, /* Nimi != Nisi */
-/*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */
- {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */
- {"njt", HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */
- {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */
- {"nko", HB_TAG_NONE }, /* Nkonya != N’Ko */
- {"nkx", HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */
- {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */
- {"nla", HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */
- {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */
- {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */
- {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */
- {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */
- {"nn", HB_TAG('N','O','R',' ')}, /* Norwegian Nynorsk -> Norwegian */
- {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */
- {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */
- {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */
- {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */
-/*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */
-/*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */
-/*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */
- {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */
- {"npl", HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */
- {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */
- {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */
- {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */
- {"nsm", HB_TAG_NONE }, /* Sumi Naga != Northern Sami */
-/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */
- {"nsu", HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */
- {"nto", HB_TAG_NONE }, /* Ntomba != Esperanto */
- {"nue", HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */
- {"nuu", HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */
- {"nuz", HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */
- {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */
- {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */
- {"nwe", HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */
- {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */
- {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */
-/*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */
- {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */
-/*{"nza", HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */
- {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
- {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */
-/*{"ojb", HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */
- {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */
- {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */
- {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */
- {"ojs", HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */
- {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */
- {"okd", HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */
- {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */
- {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
- {"okr", HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */
- {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
- {"onx", HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */
- {"oor", HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */
- {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */
- {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */
- {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */
- {"oro", HB_TAG_NONE }, /* Orokolo != Oromo */
- {"orr", HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */
- {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */
- {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */
- {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */
- {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */
- {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */
- {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */
- {"paa", HB_TAG_NONE }, /* Papuan [family] != Palestinian Aramaic */
-/*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */
- {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */
-/*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */
- {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */
- {"pap", HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */
- {"pas", HB_TAG_NONE }, /* Papasena != Pashto */
-/*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */
- {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */
- {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */
-/*{"pcc", HB_TAG('P','C','C',' ')},*/ /* Bouyei */
-/*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */
- {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */
- {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */
- {"pcm", HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */
-/*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */
- {"pdu", HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */
- {"pea", HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */
- {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */
- {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */
- {"pey", HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */
- {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */
- {"pga", HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */
-/*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */
- {"pi", HB_TAG('P','A','L',' ')}, /* Pali */
- {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */
- {"pih", HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */
- {"pil", HB_TAG_NONE }, /* Yom != Filipino */
- {"pis", HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */
- {"pkh", HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */
- {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */
- {"pl", HB_TAG('P','L','K',' ')}, /* Polish */
- {"plg", HB_TAG_NONE }, /* Pilagá != Palaung */
- {"plk", HB_TAG_NONE }, /* Kohistani Shina != Polish */
- {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */
- {"pln", HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */
- {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */
- {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */
- {"pml", HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */
-/*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */
- {"pmy", HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */
-/*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */
- {"poc", HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */
- {"poh", HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */
- {"poh", HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */
-/*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */
- {"pov", HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */
- {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */
- {"pre", HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */
-/*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */
- {"prs", HB_TAG('D','R','I',' ')}, /* Dari */
- {"prs", HB_TAG('F','A','R',' ')}, /* Dari -> Persian */
- {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */
- {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */
- {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */
- {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */
- {"pub", HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */
- {"puz", HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */
- {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */
- {"pwo", HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */
- {"pww", HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */
- {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */
- {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */
- {"qub", HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */
- {"quc", HB_TAG('Q','U','C',' ')}, /* K’iche’ */
- {"quc", HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */
- {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */
- {"qud", HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */
- {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */
- {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
- {"qug", HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */
- {"quh", HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */
- {"quh", HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */
- {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */
- {"qul", HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */
- {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */
- {"qum", HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */
- {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */
- {"qup", HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */
- {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
- {"qur", HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */
- {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */
- {"qus", HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */
- {"quv", HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */
- {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */
- {"quw", HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */
- {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */
- {"qux", HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */
- {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */
-/*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */
- {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */
- {"qva", HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */
- {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */
- {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */
- {"qvh", HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
- {"qvh", HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */
- {"qvi", HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */
- {"qvi", HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */
- {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */
- {"qvj", HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */
- {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */
- {"qvl", HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */
- {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
- {"qvm", HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */
- {"qvn", HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */
- {"qvn", HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */
- {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */
- {"qvo", HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */
- {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */
- {"qvp", HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */
- {"qvs", HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */
- {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */
- {"qvw", HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */
- {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */
- {"qvz", HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */
- {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */
- {"qwa", HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */
- {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */
- {"qwh", HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */
- {"qwh", HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */
- {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */
- {"qws", HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */
- {"qwt", HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */
- {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */
- {"qxa", HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */
- {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */
- {"qxc", HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */
- {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */
- {"qxh", HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */
- {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */
- {"qxl", HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */
- {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
- {"qxn", HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */
- {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
- {"qxo", HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */
- {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */
- {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */
- {"qxr", HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */
- {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
- {"qxt", HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */
- {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */
- {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */
- {"qxw", HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */
- {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */
-/*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */
- {"ral", HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */
-/*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */
- {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */
- {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */
- {"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */
-/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */
-/*{"rhg", HB_TAG('R','H','G',' ')},*/ /* Rohingya */
-/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */
- {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */
- {"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */
-/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */
- {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */
-/*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */
- {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */
- {"rmc", HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */
- {"rmf", HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */
- {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */
- {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */
- {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */
- {"rms", HB_TAG_NONE }, /* Romanian Sign Language != Romansh */
- {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */
- {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */
- {"rmy", HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */
- {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */
- {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */
- {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */
- {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */
- {"rop", HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */
- {"rtc", HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */
-/*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */
- {"ru", HB_TAG('R','U','S',' ')}, /* Russian */
- {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
-/*{"rup", HB_TAG('R','U','P',' ')},*/ /* Aromanian */
- {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
- {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */
- {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
- {"sad", HB_TAG_NONE }, /* Sandawe != Sadri */
- {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */
- {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */
-/*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */
-/*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */
- {"say", HB_TAG_NONE }, /* Saya != Sayisi */
- {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
- {"scf", HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */
- {"sch", HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */
- {"sci", HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */
- {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
-/*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */
-/*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */
- {"scs", HB_TAG('S','C','S',' ')}, /* North Slavey */
- {"scs", HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */
- {"scs", HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */
- {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */
- {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */
- {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */
- {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */
- {"sds", HB_TAG('B','B','R',' ')}, /* Sened -> Berber */
- {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
- {"seh", HB_TAG('S','N','A',' ')}, /* Sena */
- {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */
-/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */
- {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */
- {"sfm", HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */
- {"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */
- {"sg", HB_TAG('S','G','O',' ')}, /* Sango */
-/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */
- {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */
- {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */
-/*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */
- {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */
- {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */
- {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */
- {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */
-/*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */
- {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */
- {"shy", HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */
- {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */
- {"sib", HB_TAG_NONE }, /* Sebop != Sibe */
-/*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */
- {"sig", HB_TAG_NONE }, /* Paasaal != Silte Gurage */
- {"siz", HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */
- {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */
- {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */
- {"sjs", HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */
- {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */
- {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */
- {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */
- {"sks", HB_TAG_NONE }, /* Maia != Skolt Sami */
- {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */
- {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */
- {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */
- {"sla", HB_TAG_NONE }, /* Slavic [family] != Slavey */
- {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */
- {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */
- {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */
- {"sml", HB_TAG_NONE }, /* Central Sama != Somali */
- {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */
- {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */
- {"smt", HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */
- {"sn", HB_TAG('S','N','A','0')}, /* Shona */
- {"snh", HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */
-/*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */
- {"so", HB_TAG('S','M','L',' ')}, /* Somali */
- {"sog", HB_TAG_NONE }, /* Sogdian != Sodo Gurage */
-/*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */
- {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */
- {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */
- {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */
- {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */
- {"srb", HB_TAG_NONE }, /* Sora != Serbian */
- {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */
- {"srk", HB_TAG_NONE }, /* Serudung Murut != Saraiki */
- {"srm", HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */
- {"srn", HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */
- {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */
-/*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */
- {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */
- {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */
- {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */
- {"ssl", HB_TAG_NONE }, /* Western Sisaala != South Slavey */
- {"ssm", HB_TAG_NONE }, /* Semnam != Southern Sami */
- {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho */
- {"sta", HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */
-/*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */
- {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */
- {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */
-/*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */
- {"suq", HB_TAG('S','U','R',' ')}, /* Suri */
- {"sur", HB_TAG_NONE }, /* Mwaghavul != Suri */
- {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */
-/*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */
- {"svc", HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */
- {"sve", HB_TAG_NONE }, /* Serili != Swedish */
- {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */
- {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */
- {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */
- {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */
- {"swk", HB_TAG_NONE }, /* Malawi Sena != Swahili */
- {"swn", HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */
- {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */
-/*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */
- {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */
-/*{"syl", HB_TAG('S','Y','L',' ')},*/ /* Sylheti */
-/*{"syr", HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */
-/*{"szl", HB_TAG('S','Z','L',' ')},*/ /* Silesian */
- {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
- {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */
-/*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */
- {"taj", HB_TAG_NONE }, /* Eastern Tamang != Tajiki */
- {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */
- {"taq", HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */
- {"tas", HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */
- {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */
- {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */
- {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */
- {"tch", HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */
- {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */
- {"tcs", HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */
- {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */
- {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */
-/*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */
- {"tdx", HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */
- {"te", HB_TAG('T','E','L',' ')}, /* Telugu */
- {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */
- {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */
-/*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */
- {"tez", HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */
- {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */
- {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */
- {"tgh", HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */
- {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */
- {"tgn", HB_TAG_NONE }, /* Tandaganon != Tongan */
- {"tgr", HB_TAG_NONE }, /* Tareng != Tigre */
- {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */
- {"tgy", HB_TAG_NONE }, /* Togoyo != Tigrinya */
- {"th", HB_TAG('T','H','A',' ')}, /* Thai */
- {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */
- {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */
- {"thv", HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */
- {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */
- {"thz", HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */
- {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */
- {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */
- {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */
-/*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */
- {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */
- {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */
- {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */
- {"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */
- {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
-/*{"tli", HB_TAG('T','L','I',' ')},*/ /* Tlingit */
- {"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */
- {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */
- {"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */
- {"tmn", HB_TAG_NONE }, /* Taman (Indonesia) != Temne */
- {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */
- {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
- {"tna", HB_TAG_NONE }, /* Tacana != Tswana */
- {"tne", HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */
- {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */
- {"tnf", HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */
- {"tng", HB_TAG_NONE }, /* Tobanga != Tonga */
- {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */
- {"tod", HB_TAG('T','O','D','0')}, /* Toma */
- {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */
- {"toj", HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */
- {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */
- {"tor", HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */
- {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */
- {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */
- {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */
- {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */
- {"trk", HB_TAG_NONE }, /* Turkic [family] != Turkish */
- {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */
- {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */
- {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */
- {"tsg", HB_TAG_NONE }, /* Tausug != Tsonga */
-/*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */
- {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */
- {"ttc", HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */
- {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */
- {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */
- {"ttq", HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */
- {"tua", HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */
- {"tul", HB_TAG_NONE }, /* Tula != Tumbuka */
-/*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */
- {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */
- {"tuv", HB_TAG_NONE }, /* Turkana != Tuvin */
- {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */
-/*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */
- {"tvy", HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */
- {"tw", HB_TAG('T','W','I',' ')}, /* Twi */
- {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */
- {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */
- {"txy", HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */
- {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */
- {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */
-/*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tày */
- {"tzh", HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */
- {"tzj", HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */
- {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */
- {"tzm", HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */
- {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */
- {"tzo", HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */
- {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */
-/*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */
- {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */
- {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */
- {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */
- {"uln", HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */
-/*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */
- {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */
- {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */
- {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */
- {"usp", HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */
- {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */
- {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */
- {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */
- {"vap", HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */
- {"ve", HB_TAG('V','E','N',' ')}, /* Venda */
-/*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */
- {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
- {"vic", HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */
- {"vit", HB_TAG_NONE }, /* Viti != Vietnamese */
- {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */
- {"vkp", HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */
- {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */
- {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */
- {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
- {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
-/*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */
- {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */
- {"wag", HB_TAG_NONE }, /* Wa'ema != Wagdi */
-/*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */
- {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
- {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
- {"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */
-/*{"wci", HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */
- {"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */
- {"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */
- {"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */
- {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */
- {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */
- {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */
- {"wni", HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */
- {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
- {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */
- {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */
-/*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */
- {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */
- {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
- {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */
- {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */
- {"xbd", HB_TAG_NONE }, /* Bindal != Lü */
- {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
-/*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */
-/*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */
- {"xmg", HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */
- {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */
- {"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */
- {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */
- {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */
- {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */
- {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */
- {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */
-/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */
- {"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */
- {"xpe", HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */
- {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
- {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */
- {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */
- {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */
-/*{"xub", HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */
-/*{"xuj", HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */
- {"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */
- {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */
- {"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */
- {"yak", HB_TAG_NONE }, /* Yakama != Sakha */
-/*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */
-/*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */
- {"yba", HB_TAG_NONE }, /* Yala != Yoruba */
- {"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
- {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
- {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
-/*{"ygp", HB_TAG('Y','G','P',' ')},*/ /* Gepo */
- {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
- {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
- {"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */
-/*{"yna", HB_TAG('Y','N','A',' ')},*/ /* Aluo */
- {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
- {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */
- {"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */
- {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
-/*{"ywq", HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */
- {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */
- {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */
- {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */
-/*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */
- {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */
- {"zen", HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */
- {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */
- {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */
- {"zgh", HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */
- {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */
- {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */
- {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */
- {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */
- {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */
- {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */
- {"zlm", HB_TAG('M','L','Y',' ')}, /* Malay */
- {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */
- {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */
- {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */
- {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */
- {"znd", HB_TAG_NONE }, /* Zande [family] != Zande */
- {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
- {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */
- {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */
- {"zsm", HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */
- {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
- {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */
- {"zyb", HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */
- {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */
- {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */
- {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */
- {"zyp", HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */
-/*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */
- {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */
+static const LangTag ot_languages2[] = {
+ {HB_TAG('a','a',' ',' '), HB_TAG('A','F','R',' ')}, /* Afar */
+ {HB_TAG('a','b',' ',' '), HB_TAG('A','B','K',' ')}, /* Abkhazian */
+ {HB_TAG('a','f',' ',' '), HB_TAG('A','F','K',' ')}, /* Afrikaans */
+ {HB_TAG('a','k',' ',' '), HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */
+ {HB_TAG('a','m',' ',' '), HB_TAG('A','M','H',' ')}, /* Amharic */
+ {HB_TAG('a','n',' ',' '), HB_TAG('A','R','G',' ')}, /* Aragonese */
+ {HB_TAG('a','r',' ',' '), HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
+ {HB_TAG('a','s',' ',' '), HB_TAG('A','S','M',' ')}, /* Assamese */
+ {HB_TAG('a','v',' ',' '), HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */
+ {HB_TAG('a','y',' ',' '), HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
+ {HB_TAG('a','z',' ',' '), HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */
+ {HB_TAG('b','a',' ',' '), HB_TAG('B','S','H',' ')}, /* Bashkir */
+ {HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */
+ {HB_TAG('b','g',' ',' '), HB_TAG('B','G','R',' ')}, /* Bulgarian */
+ {HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */
+ {HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
+ {HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */
+ {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */
+ {HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */
+ {HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */
+ {HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */
+ {HB_TAG('c','a',' ',' '), HB_TAG('C','A','T',' ')}, /* Catalan */
+ {HB_TAG('c','e',' ',' '), HB_TAG('C','H','E',' ')}, /* Chechen */
+ {HB_TAG('c','h',' ',' '), HB_TAG('C','H','A',' ')}, /* Chamorro */
+ {HB_TAG('c','o',' ',' '), HB_TAG('C','O','S',' ')}, /* Corsican */
+ {HB_TAG('c','r',' ',' '), HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */
+ {HB_TAG('c','s',' ',' '), HB_TAG('C','S','Y',' ')}, /* Czech */
+ {HB_TAG('c','u',' ',' '), HB_TAG('C','S','L',' ')}, /* Church Slavonic */
+ {HB_TAG('c','v',' ',' '), HB_TAG('C','H','U',' ')}, /* Chuvash */
+ {HB_TAG('c','y',' ',' '), HB_TAG('W','E','L',' ')}, /* Welsh */
+ {HB_TAG('d','a',' ',' '), HB_TAG('D','A','N',' ')}, /* Danish */
+ {HB_TAG('d','e',' ',' '), HB_TAG('D','E','U',' ')}, /* German */
+ {HB_TAG('d','v',' ',' '), HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */
+ {HB_TAG('d','v',' ',' '), HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */
+ {HB_TAG('d','z',' ',' '), HB_TAG('D','Z','N',' ')}, /* Dzongkha */
+ {HB_TAG('e','e',' ',' '), HB_TAG('E','W','E',' ')}, /* Ewe */
+ {HB_TAG('e','l',' ',' '), HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */
+ {HB_TAG('e','n',' ',' '), HB_TAG('E','N','G',' ')}, /* English */
+ {HB_TAG('e','o',' ',' '), HB_TAG('N','T','O',' ')}, /* Esperanto */
+ {HB_TAG('e','s',' ',' '), HB_TAG('E','S','P',' ')}, /* Spanish */
+ {HB_TAG('e','t',' ',' '), HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */
+ {HB_TAG('e','u',' ',' '), HB_TAG('E','U','Q',' ')}, /* Basque */
+ {HB_TAG('f','a',' ',' '), HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */
+ {HB_TAG('f','f',' ',' '), HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */
+ {HB_TAG('f','i',' ',' '), HB_TAG('F','I','N',' ')}, /* Finnish */
+ {HB_TAG('f','j',' ',' '), HB_TAG('F','J','I',' ')}, /* Fijian */
+ {HB_TAG('f','o',' ',' '), HB_TAG('F','O','S',' ')}, /* Faroese */
+ {HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */
+ {HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
+ {HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */
+ {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */
+ {HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
+ {HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */
+ {HB_TAG('g','v',' ',' '), HB_TAG('M','N','X',' ')}, /* Manx */
+ {HB_TAG('h','a',' ',' '), HB_TAG('H','A','U',' ')}, /* Hausa */
+ {HB_TAG('h','e',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew */
+ {HB_TAG('h','i',' ',' '), HB_TAG('H','I','N',' ')}, /* Hindi */
+ {HB_TAG('h','o',' ',' '), HB_TAG('H','M','O',' ')}, /* Hiri Motu */
+ {HB_TAG('h','o',' ',' '), HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */
+ {HB_TAG('h','r',' ',' '), HB_TAG('H','R','V',' ')}, /* Croatian */
+ {HB_TAG('h','t',' ',' '), HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */
+ {HB_TAG('h','t',' ',' '), HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */
+ {HB_TAG('h','u',' ',' '), HB_TAG('H','U','N',' ')}, /* Hungarian */
+ {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */
+ {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E',' ')}, /* Armenian */
+ {HB_TAG('h','z',' ',' '), HB_TAG('H','E','R',' ')}, /* Herero */
+ {HB_TAG('i','a',' ',' '), HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */
+ {HB_TAG('i','d',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian */
+ {HB_TAG('i','d',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */
+ {HB_TAG('i','e',' ',' '), HB_TAG('I','L','E',' ')}, /* Interlingue */
+ {HB_TAG('i','g',' ',' '), HB_TAG('I','B','O',' ')}, /* Igbo */
+ {HB_TAG('i','i',' ',' '), HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */
+ {HB_TAG('i','k',' ',' '), HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */
+ {HB_TAG('i','n',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */
+ {HB_TAG('i','n',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */
+ {HB_TAG('i','o',' ',' '), HB_TAG('I','D','O',' ')}, /* Ido */
+ {HB_TAG('i','s',' ',' '), HB_TAG('I','S','L',' ')}, /* Icelandic */
+ {HB_TAG('i','t',' ',' '), HB_TAG('I','T','A',' ')}, /* Italian */
+ {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */
+ {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */
+ {HB_TAG('i','w',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */
+ {HB_TAG('j','a',' ',' '), HB_TAG('J','A','N',' ')}, /* Japanese */
+ {HB_TAG('j','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */
+ {HB_TAG('j','v',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese */
+ {HB_TAG('j','w',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */
+ {HB_TAG('k','a',' ',' '), HB_TAG('K','A','T',' ')}, /* Georgian */
+ {HB_TAG('k','g',' ',' '), HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */
+ {HB_TAG('k','i',' ',' '), HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */
+ {HB_TAG('k','j',' ',' '), HB_TAG('K','U','A',' ')}, /* Kuanyama */
+ {HB_TAG('k','k',' ',' '), HB_TAG('K','A','Z',' ')}, /* Kazakh */
+ {HB_TAG('k','l',' ',' '), HB_TAG('G','R','N',' ')}, /* Greenlandic */
+ {HB_TAG('k','m',' ',' '), HB_TAG('K','H','M',' ')}, /* Khmer */
+ {HB_TAG('k','n',' ',' '), HB_TAG('K','A','N',' ')}, /* Kannada */
+ {HB_TAG('k','o',' ',' '), HB_TAG('K','O','R',' ')}, /* Korean */
+ {HB_TAG('k','o',' ',' '), HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */
+ {HB_TAG('k','r',' ',' '), HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */
+ {HB_TAG('k','s',' ',' '), HB_TAG('K','S','H',' ')}, /* Kashmiri */
+ {HB_TAG('k','u',' ',' '), HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */
+ {HB_TAG('k','v',' ',' '), HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */
+ {HB_TAG('k','w',' ',' '), HB_TAG('C','O','R',' ')}, /* Cornish */
+ {HB_TAG('k','y',' ',' '), HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */
+ {HB_TAG('l','a',' ',' '), HB_TAG('L','A','T',' ')}, /* Latin */
+ {HB_TAG('l','b',' ',' '), HB_TAG('L','T','Z',' ')}, /* Luxembourgish */
+ {HB_TAG('l','g',' ',' '), HB_TAG('L','U','G',' ')}, /* Ganda */
+ {HB_TAG('l','i',' ',' '), HB_TAG('L','I','M',' ')}, /* Limburgish */
+ {HB_TAG('l','n',' ',' '), HB_TAG('L','I','N',' ')}, /* Lingala */
+ {HB_TAG('l','o',' ',' '), HB_TAG('L','A','O',' ')}, /* Lao */
+ {HB_TAG('l','t',' ',' '), HB_TAG('L','T','H',' ')}, /* Lithuanian */
+ {HB_TAG('l','u',' ',' '), HB_TAG('L','U','B',' ')}, /* Luba-Katanga */
+ {HB_TAG('l','v',' ',' '), HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */
+ {HB_TAG('m','g',' ',' '), HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */
+ {HB_TAG('m','h',' ',' '), HB_TAG('M','A','H',' ')}, /* Marshallese */
+ {HB_TAG('m','i',' ',' '), HB_TAG('M','R','I',' ')}, /* Maori */
+ {HB_TAG('m','k',' ',' '), HB_TAG('M','K','D',' ')}, /* Macedonian */
+ {HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
+ {HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
+ {HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
+ {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
+ {HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
+ {HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */
+ {HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
+ {HB_TAG('m','t',' ',' '), HB_TAG('M','T','S',' ')}, /* Maltese */
+ {HB_TAG('m','y',' ',' '), HB_TAG('B','R','M',' ')}, /* Burmese */
+ {HB_TAG('n','a',' ',' '), HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */
+ {HB_TAG('n','b',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */
+ {HB_TAG('n','d',' ',' '), HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */
+ {HB_TAG('n','e',' ',' '), HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */
+ {HB_TAG('n','g',' ',' '), HB_TAG('N','D','G',' ')}, /* Ndonga */
+ {HB_TAG('n','l',' ',' '), HB_TAG('N','L','D',' ')}, /* Dutch */
+ {HB_TAG('n','n',' ',' '), HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+ {HB_TAG('n','o',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */
+ {HB_TAG('n','r',' ',' '), HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */
+ {HB_TAG('n','v',' ',' '), HB_TAG('N','A','V',' ')}, /* Navajo */
+ {HB_TAG('n','v',' ',' '), HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */
+ {HB_TAG('n','y',' ',' '), HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */
+ {HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
+ {HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */
+ {HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
+ {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */
+ {HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */
+ {HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */
+ {HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */
+ {HB_TAG('p','l',' ',' '), HB_TAG('P','L','K',' ')}, /* Polish */
+ {HB_TAG('p','s',' ',' '), HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */
+ {HB_TAG('p','t',' ',' '), HB_TAG('P','T','G',' ')}, /* Portuguese */
+ {HB_TAG('q','u',' ',' '), HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */
+ {HB_TAG('r','m',' ',' '), HB_TAG('R','M','S',' ')}, /* Romansh */
+ {HB_TAG('r','n',' ',' '), HB_TAG('R','U','N',' ')}, /* Rundi */
+ {HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */
+ {HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */
+ {HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
+ {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */
+ {HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
+ {HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */
+ {HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */
+ {HB_TAG('s','g',' ',' '), HB_TAG('S','G','O',' ')}, /* Sango */
+ {HB_TAG('s','h',' ',' '), HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */
+ {HB_TAG('s','h',' ',' '), HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */
+ {HB_TAG('s','h',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */
+ {HB_TAG('s','i',' ',' '), HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */
+ {HB_TAG('s','k',' ',' '), HB_TAG('S','K','Y',' ')}, /* Slovak */
+ {HB_TAG('s','l',' ',' '), HB_TAG('S','L','V',' ')}, /* Slovenian */
+ {HB_TAG('s','m',' ',' '), HB_TAG('S','M','O',' ')}, /* Samoan */
+ {HB_TAG('s','n',' ',' '), HB_TAG('S','N','A','0')}, /* Shona */
+ {HB_TAG('s','o',' ',' '), HB_TAG('S','M','L',' ')}, /* Somali */
+ {HB_TAG('s','q',' ',' '), HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */
+ {HB_TAG('s','r',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbian */
+ {HB_TAG('s','s',' ',' '), HB_TAG('S','W','Z',' ')}, /* Swati */
+ {HB_TAG('s','t',' ',' '), HB_TAG('S','O','T',' ')}, /* Southern Sotho */
+ {HB_TAG('s','u',' ',' '), HB_TAG('S','U','N',' ')}, /* Sundanese */
+ {HB_TAG('s','v',' ',' '), HB_TAG('S','V','E',' ')}, /* Swedish */
+ {HB_TAG('s','w',' ',' '), HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */
+ {HB_TAG('t','a',' ',' '), HB_TAG('T','A','M',' ')}, /* Tamil */
+ {HB_TAG('t','e',' ',' '), HB_TAG('T','E','L',' ')}, /* Telugu */
+ {HB_TAG('t','g',' ',' '), HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */
+ {HB_TAG('t','h',' ',' '), HB_TAG('T','H','A',' ')}, /* Thai */
+ {HB_TAG('t','i',' ',' '), HB_TAG('T','G','Y',' ')}, /* Tigrinya */
+ {HB_TAG('t','k',' ',' '), HB_TAG('T','K','M',' ')}, /* Turkmen */
+ {HB_TAG('t','l',' ',' '), HB_TAG('T','G','L',' ')}, /* Tagalog */
+ {HB_TAG('t','n',' ',' '), HB_TAG('T','N','A',' ')}, /* Tswana */
+ {HB_TAG('t','o',' ',' '), HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */
+ {HB_TAG('t','r',' ',' '), HB_TAG('T','R','K',' ')}, /* Turkish */
+ {HB_TAG('t','s',' ',' '), HB_TAG('T','S','G',' ')}, /* Tsonga */
+ {HB_TAG('t','t',' ',' '), HB_TAG('T','A','T',' ')}, /* Tatar */
+ {HB_TAG('t','w',' ',' '), HB_TAG('T','W','I',' ')}, /* Twi */
+ {HB_TAG('t','w',' ',' '), HB_TAG('A','K','A',' ')}, /* Twi -> Akan */
+ {HB_TAG('t','y',' ',' '), HB_TAG('T','H','T',' ')}, /* Tahitian */
+ {HB_TAG('u','g',' ',' '), HB_TAG('U','Y','G',' ')}, /* Uyghur */
+ {HB_TAG('u','k',' ',' '), HB_TAG('U','K','R',' ')}, /* Ukrainian */
+ {HB_TAG('u','r',' ',' '), HB_TAG('U','R','D',' ')}, /* Urdu */
+ {HB_TAG('u','z',' ',' '), HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */
+ {HB_TAG('v','e',' ',' '), HB_TAG('V','E','N',' ')}, /* Venda */
+ {HB_TAG('v','i',' ',' '), HB_TAG('V','I','T',' ')}, /* Vietnamese */
+ {HB_TAG('v','o',' ',' '), HB_TAG('V','O','L',' ')}, /* Volapük */
+ {HB_TAG('w','a',' ',' '), HB_TAG('W','L','N',' ')}, /* Walloon */
+ {HB_TAG('w','o',' ',' '), HB_TAG('W','L','F',' ')}, /* Wolof */
+ {HB_TAG('x','h',' ',' '), HB_TAG('X','H','S',' ')}, /* Xhosa */
+ {HB_TAG('y','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
+ {HB_TAG('y','o',' ',' '), HB_TAG('Y','B','A',' ')}, /* Yoruba */
+ {HB_TAG('z','a',' ',' '), HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */
+ {HB_TAG('z','h',' ',' '), HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */
+ {HB_TAG('z','u',' ',' '), HB_TAG('Z','U','L',' ')}, /* Zulu */
};
+#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.
@@ -1621,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"))
- {
- /* Undetermined; Syriac (Estrangelo variant) */
- tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
- *count = 1;
- return true;
- }
- if (subtag_matches (lang_str, limit, "-syrj"))
- {
- /* Undetermined; Syriac (Western variant) */
- tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */
- *count = 1;
- return true;
- }
- if (subtag_matches (lang_str, limit, "-syrn"))
+ if (limit - lang_str >= 7)
{
- /* Undetermined; Syriac (Eastern variant) */
- tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */
- *count = 1;
- return true;
+ const char *p = strchr (lang_str, '-');
+ if (!p || p >= limit || limit - p < 5) goto out;
+ if (subtag_matches (p, limit, "-fonnapa", 8))
+ {
+ /* Undetermined; North American Phonetic Alphabet */
+ tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-polyton", 8))
+ {
+ /* Modern Greek (1453-); Polytonic Greek */
+ tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-arevmda", 8))
+ {
+ /* Armenian; Western Armenian (retired code) */
+ tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-provenc", 8))
+ {
+ /* Occitan (post 1500); Provençal */
+ tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-fonipa", 7))
+ {
+ /* Undetermined; International Phonetic Alphabet */
+ tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-geok", 5))
+ {
+ /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
+ tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-syre", 5))
+ {
+ /* Undetermined; Syriac (Estrangelo variant) */
+ tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-syrj", 5))
+ {
+ /* Undetermined; Syriac (Western variant) */
+ tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (p, limit, "-syrn", 5))
+ {
+ /* Undetermined; Syriac (Eastern variant) */
+ tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */
+ *count = 1;
+ return true;
+ }
}
+out:
switch (lang_str[0])
{
case 'a':
@@ -1702,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;
@@ -1722,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;
@@ -1742,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;
@@ -1762,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;
@@ -1782,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;
@@ -1802,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;
@@ -1822,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;
@@ -1842,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;
@@ -1862,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 */
@@ -1975,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 */
@@ -1983,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;
@@ -1997,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 */
@@ -2005,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 */
@@ -2013,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;
@@ -2027,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 */
@@ -2035,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 */
@@ -2043,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;
@@ -2057,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 */
@@ -2065,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 */
@@ -2073,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;
@@ -2087,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 */
@@ -2095,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 */
@@ -2103,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;
@@ -2117,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 */
@@ -2125,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 */
@@ -2133,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;
@@ -2147,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 */
@@ -2155,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 */
@@ -2163,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;
@@ -2177,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 */
@@ -2185,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 */
@@ -2193,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;
@@ -2207,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 */
@@ -2216,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;
@@ -2236,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 */
@@ -2258,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 */
@@ -2266,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;
@@ -2280,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 */
@@ -2289,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;
@@ -2309,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;
@@ -2329,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 */
@@ -2358,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 */
@@ -2366,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;
@@ -2380,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 */
@@ -2388,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 */
@@ -2396,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;
@@ -2410,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 */
@@ -2448,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 */
@@ -2457,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;
@@ -2477,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 */
@@ -2492,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 */
@@ -2500,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;
@@ -2514,23 +2537,31 @@ 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 */
*count = 1;
return true;
}
+ if (0 == strncmp (&lang_str[1], "nw-", 3)
+ && subtag_matches (lang_str, limit, "-th", 3))
+ {
+ /* Mon; Thailand */
+ tags[0] = HB_TAG('M','O','N','T'); /* Thailand Mon */
+ *count = 1;
+ return true;
+ }
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;
@@ -2543,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 */
@@ -2558,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 */
@@ -2566,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;
@@ -2580,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 */
@@ -2597,36 +2628,36 @@ hb_ot_tags_from_complex_language (const char *lang_str,
if (0 == strcmp (&lang_str[1], "o-nyn"))
{
/* Norwegian Nynorsk (retired code) */
- unsigned int i;
- hb_tag_t possible_tags[] = {
- HB_TAG('N','Y','N',' '), /* Norwegian Nynorsk (Nynorsk, Norwegian) */
- HB_TAG('N','O','R',' '), /* Norwegian */
- };
- for (i = 0; i < 2 && i < *count; i++)
- tags[i] = possible_tags[i];
- *count = i;
+ tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+ *count = 1;
return true;
}
break;
case 'r':
if (0 == strncmp (&lang_str[1], "o-", 2)
- && subtag_matches (lang_str, limit, "-md"))
+ && subtag_matches (lang_str, limit, "-md", 3))
{
/* Romanian; Moldova */
- tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */
- *count = 1;
+ unsigned int i;
+ hb_tag_t possible_tags[] = {
+ HB_TAG('M','O','L',' '), /* Moldavian */
+ HB_TAG('R','O','M',' '), /* Romanian */
+ };
+ for (i = 0; i < 2 && i < *count; i++)
+ tags[i] = possible_tags[i];
+ *count = i;
return true;
}
break;
case 'w':
- if (lang_matches (&lang_str[1], "uu-hant-hk"))
+ if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10))
{
/* Wu Chinese; Han (Traditional variant); Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
- if (lang_matches (&lang_str[1], "uu-hant-mo"))
+ if (lang_matches (&lang_str[1], limit, "uu-hant-mo", 10))
{
/* Wu Chinese; Han (Traditional variant); Macao */
unsigned int i;
@@ -2639,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 */
@@ -2654,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 */
@@ -2662,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;
@@ -2676,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 */
@@ -2685,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 */
@@ -2694,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;
@@ -2721,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 */
@@ -2743,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 */
@@ -2751,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;
@@ -2765,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 */
@@ -2789,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)
@@ -2803,15 +2834,15 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
case HB_TAG('A','R','K',' '): /* Rakhine */
return hb_language_from_string ("rki", -1); /* Rakhine */
case HB_TAG('A','T','H',' '): /* Athapaskan */
- return hb_language_from_string ("ath", -1); /* Athapascan [family] */
+ return hb_language_from_string ("ath", -1); /* Athapascan [collection] */
case HB_TAG('B','B','R',' '): /* Berber */
- return hb_language_from_string ("ber", -1); /* Berber [family] */
+ return hb_language_from_string ("ber", -1); /* Berber [collection] */
case HB_TAG('B','I','K',' '): /* Bikol */
return hb_language_from_string ("bik", -1); /* Bikol [macrolanguage] */
case HB_TAG('B','T','K',' '): /* Batak */
- return hb_language_from_string ("btk", -1); /* Batak [family] */
+ return hb_language_from_string ("btk", -1); /* Batak [collection] */
case HB_TAG('C','P','P',' '): /* Creoles */
- return hb_language_from_string ("crp", -1); /* Creoles and pidgins [family] */
+ return hb_language_from_string ("crp", -1); /* Creoles and pidgins [collection] */
case HB_TAG('C','R','R',' '): /* Carrier */
return hb_language_from_string ("crx", -1); /* Carrier */
case HB_TAG('D','G','R',' '): /* Dogri (macrolanguage) */
@@ -2828,6 +2859,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */
case HB_TAG('G','O','N',' '): /* Gondi */
return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */
+ case HB_TAG('H','M','A',' '): /* High Mari */
+ return hb_language_from_string ("mrj", -1); /* Western Mari */
case HB_TAG('H','M','N',' '): /* Hmong */
return hb_language_from_string ("hmn", -1); /* Hmong [macrolanguage] */
case HB_TAG('H','N','D',' '): /* Hindko */
@@ -2837,7 +2870,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
case HB_TAG('I','B','A',' '): /* Iban */
return hb_language_from_string ("iba", -1); /* Iban */
case HB_TAG('I','J','O',' '): /* Ijo */
- return hb_language_from_string ("ijo", -1); /* Ijo [family] */
+ return hb_language_from_string ("ijo", -1); /* Ijo [collection] */
case HB_TAG('I','N','U',' '): /* Inuktitut */
return hb_language_from_string ("iu", -1); /* Inuktitut [macrolanguage] */
case HB_TAG('I','P','K',' '): /* Inupiat */
@@ -2863,11 +2896,13 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
case HB_TAG('K','P','L',' '): /* Kpelle */
return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */
case HB_TAG('K','R','N',' '): /* Karen */
- return hb_language_from_string ("kar", -1); /* Karen [family] */
+ return hb_language_from_string ("kar", -1); /* Karen [collection] */
case HB_TAG('K','U','I',' '): /* Kui */
return hb_language_from_string ("uki", -1); /* Kui (India) */
case HB_TAG('K','U','R',' '): /* Kurdish */
return hb_language_from_string ("ku", -1); /* Kurdish [macrolanguage] */
+ case HB_TAG('L','M','A',' '): /* Low Mari */
+ return hb_language_from_string ("mhr", -1); /* Eastern Mari */
case HB_TAG('L','U','H',' '): /* Luyia */
return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */
case HB_TAG('L','V','I',' '): /* Latvian */
@@ -2884,10 +2919,12 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
case HB_TAG('M','O','L',' '): /* Moldavian */
return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
+ case HB_TAG('M','O','N','T'): /* Thailand Mon */
+ return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */
case HB_TAG('M','Y','N',' '): /* Mayan */
- return hb_language_from_string ("myn", -1); /* Mayan [family] */
+ return hb_language_from_string ("myn", -1); /* Mayan [collection] */
case HB_TAG('N','A','H',' '): /* Nahuatl */
- return hb_language_from_string ("nah", -1); /* Nahuatl [family] */
+ return hb_language_from_string ("nah", -1); /* Nahuatl [collection] */
case HB_TAG('N','E','P',' '): /* Nepali */
return hb_language_from_string ("ne", -1); /* Nepali [macrolanguage] */
case HB_TAG('N','I','S',' '): /* Nisi */
@@ -2914,6 +2951,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */
case HB_TAG('R','A','J',' '): /* Rajasthani */
return hb_language_from_string ("raj", -1); /* Rajasthani [macrolanguage] */
+ case HB_TAG('R','O','M',' '): /* Romanian */
+ return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
case HB_TAG('S','Q','I',' '): /* Albanian */
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 1837063af..f6ba3b0d4 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -41,6 +41,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
switch ((hb_tag_t) script)
{
case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT;
+ case HB_SCRIPT_MATH: return HB_OT_TAG_MATH_SCRIPT;
/* KATAKANA and HIRAGANA both map to 'kana' */
case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a');
@@ -63,6 +64,8 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
{
if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
return HB_SCRIPT_INVALID;
+ if (unlikely (tag == HB_OT_TAG_MATH_SCRIPT))
+ return HB_SCRIPT_MATH;
/* This side of the conversion is fully algorithmic. */
@@ -186,48 +189,48 @@ 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);
+ /* Same as hb_language_matches(); duplicated. */
+
+ 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); }
@@ -262,16 +265,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, '-');
@@ -280,17 +286,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;
+
+ if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) ||
+ hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx))
{
+ last_tag_idx = tag_idx;
unsigned int i;
while (tag_idx != 0 &&
- 0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language))
+ ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language)
tag_idx--;
for (i = 0;
i < *count &&
- tag_idx + i < ARRAY_LENGTH (ot_languages) &&
+ tag_idx + i < ot_languages_len &&
ot_languages[tag_idx + i].tag != HB_TAG_NONE &&
- 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language);
+ ot_languages[tag_idx + i].language == ot_languages[tag_idx].language;
i++)
tags[i] = ot_languages[tag_idx + i].tag;
*count = i;
@@ -298,6 +329,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) {
@@ -306,6 +338,7 @@ hb_ot_tags_from_language (const char *lang_str,
*count = 1;
return;
}
+#endif
*count = 0;
}
@@ -450,15 +483,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
@@ -530,7 +577,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
else
{
int shift;
- memcpy (buf, lang_str, len);
+ hb_memcpy (buf, lang_str, len);
if (lang_str[0] != 'x' || lang_str[1] != '-') {
buf[len++] = '-';
buf[len++] = 'x';
@@ -554,16 +601,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_languages2[i].cmp (&ot_languages2[i - 1]);
+ if (c > 0)
+ {
+ fprintf (stderr, "ot_languages2 not sorted at index %d: %08x %d %08x\n",
+ i, ot_languages2[i-1].language, c, ot_languages2[i].language);
+ abort();
+ }
+ }
+#ifndef HB_NO_LANGUAGE_LONG
+ for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++)
{
- int c = ot_languages[i].cmp (&ot_languages[i - 1]);
+ int c = ot_languages3[i].cmp (&ot_languages3[i - 1]);
if (c > 0)
{
- fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
- i, ot_languages[i-1].language, c, ot_languages[i].language);
+ fprintf (stderr, "ot_languages3 not sorted at index %d: %08x %d %08x\n",
+ i, ot_languages3[i-1].language, c, ot_languages3[i].language);
abort();
}
}
+#endif
}
int
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index 65f26c1d2..cc5c5c006 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -28,6 +28,8 @@
#define HB_OT_VAR_AVAR_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-ot-var-common.hh"
+
/*
* avar -- Axis Variations
@@ -40,6 +42,28 @@
namespace OT {
+/* "Spec": https://github.com/be-fonts/boring-expansion-spec/issues/14 */
+struct avarV2Tail
+{
+ friend struct avar;
+
+ bool sanitize (hb_sanitize_context_t *c,
+ const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (varIdxMap.sanitize (c, base) &&
+ varStore.sanitize (c, base));
+ }
+
+ protected:
+ Offset32To<DeltaSetIndexMap> varIdxMap; /* Offset from the beginning of 'avar' table. */
+ Offset32To<VariationStore> varStore; /* Offset from the beginning of 'avar' table. */
+
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+
struct AxisValueMap
{
bool sanitize (hb_sanitize_context_t *c) const
@@ -106,12 +130,24 @@ struct avar
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
+ bool has_data () const { return version.to_int (); }
+
+ const SegmentMaps* get_segment_maps () const
+ { return &firstAxisSegmentMaps; }
+
+ unsigned get_axis_count () const
+ { return axisCount; }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!(version.sanitize (c) &&
- version.major == 1 &&
- c->check_struct (this))))
+ if (!(version.sanitize (c) &&
+ (version.major == 1
+#ifndef HB_NO_AVAR2
+ || version.major == 2
+#endif
+ ) &&
+ c->check_struct (this)))
return_trace (false);
const SegmentMaps *map = &firstAxisSegmentMaps;
@@ -123,6 +159,15 @@ struct avar
map = &StructAfter<SegmentMaps> (*map);
}
+#ifndef HB_NO_AVAR2
+ if (version.major < 2)
+ return_trace (true);
+
+ const auto &v2 = * (const avarV2Tail *) map;
+ if (unlikely (!v2.sanitize (c, this)))
+ return_trace (false);
+#endif
+
return_trace (true);
}
@@ -136,6 +181,36 @@ struct avar
coords[i] = map->map (coords[i]);
map = &StructAfter<SegmentMaps> (*map);
}
+
+#ifndef HB_NO_AVAR2
+ if (version.major < 2)
+ return;
+
+ for (; count < axisCount; count++)
+ map = &StructAfter<SegmentMaps> (*map);
+
+ const auto &v2 = * (const avarV2Tail *) map;
+
+ const auto &varidx_map = this+v2.varIdxMap;
+ const auto &var_store = this+v2.varStore;
+ auto *var_store_cache = var_store.create_cache ();
+
+ hb_vector_t<int> out;
+ out.alloc (coords_length);
+ for (unsigned i = 0; i < coords_length; i++)
+ {
+ int v = coords[i];
+ uint32_t varidx = varidx_map.map (i);
+ float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache);
+ v += roundf (delta);
+ v = hb_clamp (v, -(1<<14), +(1<<14));
+ out.push (v);
+ }
+ for (unsigned i = 0; i < coords_length; i++)
+ coords[i] = out[i];
+
+ OT::VariationStore::destroy_cache (var_store_cache);
+#endif
}
void unmap_coords (int *coords, unsigned int coords_length) const
diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh
index 0eafb949d..4997c2e2e 100644
--- a/src/hb-ot-var-common.hh
+++ b/src/hb-ot-var-common.hh
@@ -31,12 +31,13 @@
namespace OT {
-struct DeltaSetIndexMapFormat0
+template <typename MapCountT>
+struct DeltaSetIndexMapFormat01
{
friend struct DeltaSetIndexMap;
private:
- DeltaSetIndexMapFormat0* copy (hb_serialize_context_t *c) const
+ DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
@@ -46,7 +47,7 @@ struct DeltaSetIndexMapFormat0
HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
if (unlikely (!p)) return_trace (nullptr);
- memcpy (p, this, HBUINT8::static_size * total_size);
+ hb_memcpy (p, this, HBUINT8::static_size * total_size);
return_trace (out);
}
@@ -128,56 +129,12 @@ struct DeltaSetIndexMapFormat0
HBUINT8 format; /* Format identifier--format = 0 */
HBUINT8 entryFormat; /* A packed field that describes the compressed
* representation of delta-set indices. */
- HBUINT16 mapCount; /* The number of mapping entries. */
+ MapCountT mapCount; /* The number of mapping entries. */
UnsizedArrayOf<HBUINT8>
mapDataZ; /* The delta-set index mapping data. */
public:
- DEFINE_SIZE_ARRAY (4, mapDataZ);
-};
-
-struct DeltaSetIndexMapFormat1
-{
- friend struct DeltaSetIndexMap;
-
- private:
- DeltaSetIndexMapFormat1* copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- unsigned total_size = min_size + mapCount * get_width ();
- HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
- if (unlikely (!p)) return_trace (nullptr);
-
- memcpy (p, this, HBUINT8::static_size * total_size);
- return_trace (out);
- }
-
- unsigned get_map_count () const { return mapCount; }
- unsigned get_width () const { return ((entryFormat >> 4) & 3) + 1; }
- unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- c->check_range (mapDataZ.arrayZ,
- mapCount,
- get_width ()));
- }
-
- protected:
- HBUINT8 format; /* Format identifier--format = 1 */
- HBUINT8 entryFormat; /* A packed field that describes the compressed
- * representation of delta-set indices. */
- HBUINT32 mapCount; /* The number of mapping entries. */
- UnsizedArrayOf<HBUINT8>
- mapDataZ; /* The delta-set index mapping data. */
-
- public:
- DEFINE_SIZE_ARRAY (6, mapDataZ);
+ DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
};
struct DeltaSetIndexMap
@@ -186,8 +143,11 @@ struct DeltaSetIndexMap
bool serialize (hb_serialize_context_t *c, const T &plan)
{
TRACE_SERIALIZE (this);
+ unsigned length = plan.get_output_map ().length;
+ u.format = length <= 0xFFFF ? 0 : 1;
switch (u.format) {
case 0: return_trace (u.format0.serialize (c, plan));
+ case 1: return_trace (u.format1.serialize (c, plan));
default:return_trace (false);
}
}
@@ -196,6 +156,7 @@ struct DeltaSetIndexMap
{
switch (u.format) {
case 0: return (u.format0.map (v));
+ case 1: return (u.format1.map (v));
default:return v;
}
}
@@ -250,14 +211,33 @@ struct DeltaSetIndexMap
protected:
union {
- HBUINT8 format; /* Format identifier */
- DeltaSetIndexMapFormat0 format0;
- DeltaSetIndexMapFormat1 format1;
+ HBUINT8 format; /* Format identifier */
+ DeltaSetIndexMapFormat01<HBUINT16> format0;
+ DeltaSetIndexMapFormat01<HBUINT32> format1;
} u;
public:
DEFINE_SIZE_UNION (1, format);
};
+
+struct VarStoreInstancer
+{
+ VarStoreInstancer (const VariationStore &varStore,
+ const DeltaSetIndexMap &varIdxMap,
+ hb_array_t<int> coords) :
+ varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
+
+ operator bool () const { return bool (coords); }
+
+ float operator() (uint32_t varIdx, unsigned short offset = 0) const
+ { return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); }
+
+ const VariationStore &varStore;
+ const DeltaSetIndexMap &varIdxMap;
+ hb_array_t<int> coords;
+};
+
+
} /* namespace OT */
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 05f289db2..c1d57a002 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -44,9 +44,47 @@ struct InstanceRecord
{
friend struct fvar;
- hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
+ hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
{ return coordinatesZ.as_array (axis_count); }
+ bool subset (hb_subset_context_t *c,
+ unsigned axis_count,
+ bool has_postscript_nameid) const
+ {
+ TRACE_SUBSET (this);
+ if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
+ if (unlikely (!c->serializer->embed (flags))) return_trace (false);
+
+ const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+ const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
+ for (unsigned i = 0 ; i < axis_count; i++)
+ {
+ uint32_t *axis_tag;
+ // only keep instances whose coordinates == pinned axis location
+ if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
+
+ if (axes_location->has (*axis_tag) &&
+ fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
+ return_trace (false);
+
+ if (!c->plan->axes_index_map->has (i))
+ continue;
+
+ if (!c->serializer->embed (coords[i]))
+ return_trace (false);
+ }
+
+ if (has_postscript_nameid)
+ {
+ NameID name_id;
+ name_id = StructAfter<NameID> (coords);
+ if (!c->serializer->embed (name_id))
+ return_trace (false);
+ }
+
+ return_trace (true);
+ }
+
bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
{
TRACE_SANITIZE (this);
@@ -58,7 +96,7 @@ struct InstanceRecord
NameID subfamilyNameID;/* The name ID for entries in the 'name' table
* that provide subfamily names for this instance. */
HBUINT16 flags; /* Reserved for future use — set to 0. */
- UnsizedArrayOf<HBFixed>
+ UnsizedArrayOf<F16DOT16>
coordinatesZ; /* The coordinates array for this instance. */
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
// * table that provide PostScript names for this
@@ -96,6 +134,8 @@ struct AxisRecord
info->reserved = 0;
}
+ hb_tag_t get_axis_tag () const { return axisTag; }
+
int normalize_axis_value (float v) const
{
float min_value, default_value, max_value;
@@ -133,7 +173,6 @@ struct AxisRecord
return_trace (c->check_struct (this));
}
- protected:
void get_coordinates (float &min, float &default_, float &max) const
{
default_ = defaultValue / 65536.f;
@@ -142,12 +181,17 @@ struct AxisRecord
max = hb_max (default_, maxValue / 65536.f);
}
+ float get_default () const
+ {
+ return defaultValue / 65536.f;
+ }
+
public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
protected:
- HBFixed minValue; /* The minimum coordinate value for the axis. */
- HBFixed defaultValue; /* The default coordinate value for the axis. */
- HBFixed maxValue; /* The maximum coordinate value for the axis. */
+ F16DOT16 minValue; /* The minimum coordinate value for the axis. */
+ F16DOT16 defaultValue; /* The default coordinate value for the axis. */
+ F16DOT16 maxValue; /* The maximum coordinate value for the axis. */
public:
HBUINT16 flags; /* Axis flags. */
NameID axisNameID; /* The name ID for entries in the 'name' table that
@@ -213,7 +257,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 +265,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
@@ -262,32 +306,99 @@ struct fvar
if (coords_length && *coords_length)
{
- hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
- .sub_array (0, *coords_length);
+ hb_array_t<const F16DOT16> instanceCoords = instance->get_coordinates (axisCount)
+ .sub_array (0, coords_length);
for (unsigned int i = 0; i < instanceCoords.length; i++)
coords[i] = instanceCoords.arrayZ[i].to_float ();
}
return axisCount;
}
- void collect_name_ids (hb_set_t *nameids) const
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ hb_set_t *nameids /* IN/OUT */) const
{
if (!has_data ()) return;
+ hb_map_t pinned_axes;
- + get_axes ()
- | hb_map (&AxisRecord::get_name_id)
- | hb_sink (nameids)
- ;
+ auto axis_records = get_axes ();
+ for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+ {
+ hb_tag_t axis_tag = axis_records[i].get_axis_tag ();
+ if (user_axes_location->has (axis_tag))
+ {
+ pinned_axes.set (i, axis_tag);
+ continue;
+ }
+
+ nameids->add (axis_records[i].get_name_id ());
+ }
+
+ for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+ {
+ const InstanceRecord *instance = get_instance (i);
+
+ if (hb_any (+ hb_enumerate (instance->get_coordinates (axisCount))
+ | hb_filter (pinned_axes, hb_first)
+ | hb_map ([&] (const hb_pair_t<unsigned, const F16DOT16&>& _)
+ {
+ hb_tag_t axis_tag = pinned_axes.get (_.first);
+ float location = user_axes_location->get (axis_tag);
+ if (fabs ((double)location - (double)_.second.to_float ()) > 0.001) return true;
+ return false;
+ })
+ ))
+ continue;
+
+ nameids->add (instance->subfamilyNameID);
+
+ if (instanceSize >= axisCount * 4 + 6)
+ {
+ unsigned post_script_name_id = StructAfter<NameID> (instance->get_coordinates (axisCount));
+ if (post_script_name_id != HB_OT_NAME_ID_INVALID) nameids->add (post_script_name_id);
+ }
+ }
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ unsigned retained_axis_count = c->plan->axes_index_map->get_population ();
+ if (!retained_axis_count) //all axes are pinned
+ return_trace (false);
+
+ fvar *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
- + hb_range ((unsigned) instanceCount)
- | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); })
- | hb_sink (nameids)
- ;
+ if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
- + hb_range ((unsigned) instanceCount)
- | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); })
- | hb_sink (nameids)
- ;
+ bool has_postscript_nameid = false;
+ if (instanceSize >= axisCount * 4 + 6)
+ has_postscript_nameid = true;
+
+ if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ auto axes_records = get_axes ();
+ for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+ {
+ if (!c->plan->axes_index_map->has (i)) continue;
+ if (unlikely (!c->serializer->embed (axes_records[i])))
+ return_trace (false);
+ }
+
+ if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+ {
+ const InstanceRecord *instance = get_instance (i);
+ auto snap = c->serializer->snapshot ();
+ if (!instance->subset (c, axisCount, has_postscript_nameid))
+ c->serializer->revert (snap);
+ }
+ return_trace (true);
}
public:
@@ -315,8 +426,8 @@ struct fvar
HBUINT16 instanceCount; /* The number of named instances defined in the font
* (the number of records in the instances array). */
HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set
- * to either axisCount * sizeof(HBFixed) + 4, or to
- * axisCount * sizeof(HBFixed) + 6. */
+ * to either axisCount * sizeof(F16DOT16) + 4, or to
+ * axisCount * sizeof(F16DOT16) + 6. */
public:
DEFINE_SIZE_STATIC (16);
diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh
index 49b5532d4..e02063ca4 100644
--- a/src/hb-ot-var-gvar-table.hh
+++ b/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,23 @@ 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, false)))
+ return;
+ auto arrayZ = this->arrayZ + old_len;
+ unsigned count = a.length;
+ hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
}
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 +81,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 +101,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 +220,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;
@@ -218,8 +230,8 @@ struct GlyphVariationData
{
return (index < var_data->tupleVarCount.get_count ()) &&
var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
- var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) &&
- current_tuple->get_size (axis_count);
+ var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (),
+ current_tuple->get_size (axis_count)));
}
bool move_to_next ()
@@ -258,7 +270,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,52 +278,51 @@ 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++;
+ unsigned 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, false))) return false;
- unsigned int n = 0;
- uint16_t i = 0;
+ unsigned n = 0;
+ unsigned i = 0;
while (i < count)
{
- if (unlikely (!bytes.check_range (p))) return false;
- uint16_t j;
- uint8_t control = *p++;
- uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+ if (unlikely (p + 1 > end)) return false;
+ unsigned control = *p++;
+ unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+ if (unlikely (i + run_count > count)) return false;
+ unsigned j;
if (control & POINTS_ARE_WORDS)
{
- for (j = 0; j < run_count && i < count; j++, i++)
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
- return false;
n += *(const HBUINT16 *)p;
- points[i] = n;
+ points.arrayZ[i] = n;
p += HBUINT16::static_size;
}
}
else
{
- for (j = 0; j < run_count && i < count; j++, i++)
+ if (unlikely (p + run_count > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (!bytes.check_range (p))) return false;
n += *p++;
- points[i] = n;
+ points.arrayZ[i] = n;
}
}
- if (j < run_count) return false;
}
return true;
}
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
{
@@ -320,34 +331,37 @@ struct GlyphVariationData
DELTA_RUN_COUNT_MASK = 0x3F
};
- unsigned int i = 0;
- unsigned int count = deltas.length;
+ unsigned i = 0;
+ unsigned count = deltas.length;
while (i < count)
{
- if (unlikely (!bytes.check_range (p))) return false;
- uint8_t control = *p++;
- unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
- unsigned int j;
+ if (unlikely (p + 1 > end)) return false;
+ unsigned control = *p++;
+ unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+ if (unlikely (i + run_count > count)) return false;
+ unsigned j;
if (control & DELTAS_ARE_ZERO)
- for (j = 0; j < run_count && i < count; j++, i++)
- deltas[i] = 0;
+ {
+ for (j = 0; j < run_count; j++, i++)
+ deltas.arrayZ[i] = 0;
+ }
else if (control & DELTAS_ARE_WORDS)
- for (j = 0; j < run_count && i < count; j++, i++)
+ {
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
- return false;
- deltas[i] = *(const HBINT16 *) p;
+ deltas.arrayZ[i] = * (const HBINT16 *) p;
p += HBUINT16::static_size;
}
+ }
else
- for (j = 0; j < run_count && i < count; j++, i++)
+ {
+ if (unlikely (p + run_count > end)) return false;
+ for (j = 0; j < run_count; j++, i++)
{
- if (unlikely (!bytes.check_range (p)))
- return false;
- deltas[i] = *(const HBINT8 *) p++;
+ deltas.arrayZ[i] = * (const HBINT8 *) p++;
}
- if (j < run_count)
- return false;
+ }
}
return true;
}
@@ -390,16 +404,13 @@ struct gvar
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (version.major == 1) &&
- (glyphCount == c->get_num_glyphs ()) &&
sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
(is_long_offset () ?
c->check_array (get_long_offset_array (), glyphCount+1) :
- c->check_array (get_short_offset_array (), glyphCount+1)) &&
- c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0),
- get_offset (glyphCount) - get_offset (0)));
+ c->check_array (get_short_offset_array (), glyphCount+1)));
}
- /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */
+ /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */
bool sanitize (hb_sanitize_context_t *c) const
{ return sanitize_shallow (c); }
@@ -443,7 +454,7 @@ struct gvar
F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
if (!tuples) return_trace (false);
out->sharedTuples = (char *) tuples - (char *) out;
- memcpy (tuples, this+sharedTuples, shared_tuple_size);
+ hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
}
char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
@@ -466,7 +477,7 @@ struct gvar
((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
if (var_data_bytes.length > 0)
- memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+ hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
subset_data += var_data_bytes.length;
glyph_offset += var_data_bytes.length;
}
@@ -482,7 +493,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 +503,11 @@ 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;
+ _hb_compiler_memory_r_barrier ();
+ return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
+ }
const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
@@ -498,24 +515,22 @@ struct gvar
public:
struct accelerator_t
{
- void init (hb_face_t *face)
+ accelerator_t (hb_face_t *face)
{ table = hb_sanitize_context_t ().reference_table<gvar> (face); }
- void fini () { table.destroy (); }
+ ~accelerator_t () { table.destroy (); }
private:
- struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
- 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.arrayZ[target].*m;
+ float prev_val = points.arrayZ[prev].*m;
+ float next_val = points.arrayZ[next].*m;
+ float prev_delta = deltas.arrayZ[prev].*m;
+ float next_delta = deltas.arrayZ[next].*m;
if (prev_val == next_val)
return (prev_delta == next_delta) ? prev_delta : 0.f;
@@ -526,18 +541,18 @@ 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)
{ return (i >= end) ? start : (i + 1); }
public:
- bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
+ bool apply_deltas_to_points (hb_codepoint_t glyph,
+ hb_array_t<int> coords,
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 (!coords) return true;
if (unlikely (glyph >= table->glyphCount)) return true;
@@ -550,22 +565,26 @@ struct gvar
return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
- contour_point_vector_t orig_points;
- orig_points.resize (points.length);
- for (unsigned int i = 0; i < orig_points.length; i++)
- orig_points[i] = points[i];
+ contour_point_vector_t orig_points_vec;
+ orig_points_vec.extend (points);
+ if (unlikely (orig_points_vec.in_error ())) return false;
+ auto orig_points = orig_points_vec.as_array ();
- contour_point_vector_t deltas; /* flag is used to indicate referenced point */
- deltas.resize (points.length);
+ contour_point_vector_t deltas_vec; /* flag is used to indicate referenced point */
+ if (unlikely (!deltas_vec.resize (points.length, false))) return false;
+ auto deltas = deltas_vec.as_array ();
hb_vector_t<unsigned> end_points;
for (unsigned i = 0; i < points.length; ++i)
- if (points[i].is_end_point)
+ if (points.arrayZ[i].is_end_point)
end_points.push (i);
- int *coords = font->coords;
- unsigned num_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,89 +594,106 @@ 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;
- if (iterator.current_tuple->has_private_points () &&
- !GlyphVariationData::unpack_points (p, private_indices, bytes))
+ 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, end))
return false;
- const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
+ const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
unsigned int num_deltas = apply_to_all ? points.length : indices.length;
- 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, false))) return false;
+ if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
+ if (unlikely (!y_deltas.resize (num_deltas, false))) 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;
- }
+ hb_memset (deltas.arrayZ, 0, deltas.get_size ());
+
+ unsigned ref_points = 0;
+ if (scalar != 1.0f)
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = apply_to_all ? i : indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ ref_points += !delta.flag;
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i] * scalar;
+ delta.y += y_deltas.arrayZ[i] * scalar;
+ }
+ else
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = apply_to_all ? i : indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ ref_points += !delta.flag;
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i];
+ delta.y += y_deltas.arrayZ[i];
+ }
/* infer deltas for unreferenced points */
- unsigned start_point = 0;
- for (unsigned c = 0; c < end_points.length; c++)
+ if (ref_points && ref_points < orig_points.length)
{
- unsigned end_point = end_points[c];
+ unsigned start_point = 0;
+ for (unsigned c = 0; c < end_points.length; c++)
+ {
+ unsigned end_point = end_points.arrayZ[c];
- /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
- unsigned unref_count = 0;
- for (unsigned i = start_point; i <= end_point; i++)
- if (!deltas[i].flag) unref_count++;
+ /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+ unsigned unref_count = 0;
+ for (unsigned i = start_point; i < end_point + 1; i++)
+ unref_count += deltas.arrayZ[i].flag;
+ unref_count = (end_point - start_point + 1) - unref_count;
- unsigned j = start_point;
- if (unref_count == 0 || unref_count > end_point - start_point)
- goto no_more_gaps;
+ unsigned j = start_point;
+ if (unref_count == 0 || unref_count > end_point - start_point)
+ goto no_more_gaps;
- for (;;)
- {
- /* Locate the next gap of unreferenced points between two referenced points prev and next.
- * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
- */
- unsigned int prev, next, i;
for (;;)
{
- i = j;
- j = next_index (i, start_point, end_point);
- if (deltas[i].flag && !deltas[j].flag) break;
- }
- prev = j = i;
- for (;;)
- {
- i = j;
- j = next_index (i, start_point, end_point);
- if (!deltas[i].flag && deltas[j].flag) break;
- }
- next = j;
- /* Infer deltas for all unref points in the gap between prev and next */
- i = prev;
- for (;;)
- {
- 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);
- if (--unref_count == 0) goto no_more_gaps;
+ /* Locate the next gap of unreferenced points between two referenced points prev and next.
+ * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+ */
+ unsigned int prev, next, i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (deltas.arrayZ[i].flag && !deltas.arrayZ[j].flag) break;
+ }
+ prev = j = i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (!deltas.arrayZ[i].flag && deltas.arrayZ[j].flag) break;
+ }
+ next = j;
+ /* Infer deltas for all unref points in the gap between prev and next */
+ i = prev;
+ for (;;)
+ {
+ i = next_index (i, start_point, end_point);
+ if (i == next) break;
+ deltas.arrayZ[i].x = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::x);
+ deltas.arrayZ[i].y = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::y);
+ if (--unref_count == 0) goto no_more_gaps;
+ }
}
+ no_more_gaps:
+ start_point = end_point + 1;
}
-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 ());
@@ -695,10 +731,12 @@ no_more_gaps:
offsetZ; /* Offsets from the start of the GlyphVariationData array
* to each GlyphVariationData table. */
public:
- DEFINE_SIZE_MIN (20);
+ DEFINE_SIZE_ARRAY (20, offsetZ);
};
-struct gvar_accelerator_t : gvar::accelerator_t {};
+struct gvar_accelerator_t : gvar::accelerator_t {
+ gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {}
+};
} /* namespace OT */
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 074b6a378..53355c507 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -177,9 +177,6 @@ struct hvarvvar_subset_plan_t
inner_maps.resize (var_store->get_sub_table_count ());
- for (unsigned int i = 0; i < inner_maps.length; i++)
- inner_maps[i].init ();
-
if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
bool retain_adv_map = false;
@@ -229,8 +226,8 @@ struct hvarvvar_subset_plan_t
for (unsigned int i = 0; i < inner_sets.length; i++)
hb_set_destroy (inner_sets[i]);
hb_set_destroy (adv_set);
- inner_maps.fini_deep ();
- index_map_plans.fini_deep ();
+ inner_maps.fini ();
+ index_map_plans.fini ();
}
hb_inc_bimap_t outer_map;
@@ -322,23 +319,27 @@ 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_delta_unscaled (hb_codepoint_t glyph,
+ const int *coords, unsigned int coord_count,
+ 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,
+ coords, coord_count,
+ store_cache);
}
- float get_side_bearing_var (hb_codepoint_t glyph,
- const int *coords, unsigned int coord_count) const
+ bool get_lsb_delta_unscaled (hb_codepoint_t glyph,
+ const int *coords, unsigned int coord_count,
+ float *lsb) const
{
- if (!has_side_bearing_deltas ()) return 0.f;
+ if (!lsbMap) return false;
uint32_t varidx = (this+lsbMap).map (glyph);
- return (this+varStore).get_delta (varidx, coords, coord_count);
+ *lsb = (this+varStore).get_delta (varidx, coords, coord_count);
+ return true;
}
- 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>
@@ -390,6 +391,16 @@ struct VVAR : HVARVVAR {
bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
+ bool get_vorg_delta_unscaled (hb_codepoint_t glyph,
+ const int *coords, unsigned int coord_count,
+ float *delta) const
+ {
+ if (!vorgMap) return false;
+ uint32_t varidx = (this+vorgMap).map (glyph);
+ *delta = (this+varStore).get_delta (varidx, coords, coord_count);
+ return true;
+ }
+
protected:
Offset32To<DeltaSetIndexMap>
vorgMap; /* Offset to vertical-origin var-idx mapping. */
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index 208db4674..420366fbb 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -43,7 +43,7 @@ struct VariationValueRecord
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
- HBUINT32 varIdx; /* Outer/inner index into VariationStore item. */
+ VarIdx varIdx; /* Outer/inner index into VariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index 6b42b45cd..f000f2726 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face includes any OpenType variation data in the `fvar` table.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 1.4.2
**/
@@ -162,7 +162,7 @@ hb_ot_var_get_axis_infos (hb_face_t *face,
* Fetches the variation-axis information corresponding to the specified axis tag
* in the specified face.
*
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
*
* Since: 2.2.0
**/
@@ -303,6 +303,9 @@ hb_ot_var_normalize_variations (hb_face_t *face,
* values for the axis are mapped to the interval [-1,1], with the default
* axis value mapped to 0.
*
+ * The normalized values have 14 bits of fixed-point sub-integer precision as per
+ * OpenType specification.
+ *
* Any additional scaling defined in the face's `avar` table is also
* applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar
*
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index ce201d3b4..05147cc25 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -109,7 +109,7 @@ typedef enum { /*< flags >*/
* @tag: The #hb_tag_t tag identifying the design variation of the axis
* @name_id: The `name` table Name ID that provides display names for the axis
* @flags: The #hb_ot_var_axis_flags_t flags for the axis
- * @min_value: The mininum value on the variation axis that the font covers
+ * @min_value: The minimum value on the variation axis that the font covers
* @default_value: The position on the variation axis corresponding to the font's defaults
* @max_value: The maximum value on the variation axis that the font covers
*
diff --git a/src/hb-pool.hh b/src/hb-pool.hh
index dcf8f6627..e4bb64f62 100644
--- a/src/hb-pool.hh
+++ b/src/hb-pool.hh
@@ -35,15 +35,13 @@ template <typename T, unsigned ChunkLen = 16>
struct hb_pool_t
{
hb_pool_t () : next (nullptr) {}
- ~hb_pool_t () { fini (); }
-
- void fini ()
+ ~hb_pool_t ()
{
next = nullptr;
- for (chunk_t *_ : chunks) hb_free (_);
-
- chunks.fini ();
+ + hb_iter (chunks)
+ | hb_apply (hb_free)
+ ;
}
T* alloc ()
@@ -60,7 +58,7 @@ struct hb_pool_t
T* obj = next;
next = * ((T**) next);
- memset (obj, 0, sizeof (T));
+ hb_memset (obj, 0, sizeof (T));
return obj;
}
diff --git a/src/hb-priority-queue.hh b/src/hb-priority-queue.hh
index 7d799ae90..ac76b7d95 100644
--- a/src/hb-priority-queue.hh
+++ b/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,16 +51,21 @@ 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);
+
+ if (!is_empty ())
+ bubble_down (0);
return result;
}
@@ -104,6 +102,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 +113,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.arrayZ[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 +130,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 +144,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/src/hb-repacker.hh b/src/hb-repacker.hh
index 26faa56ea..7a3143cec 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -29,1060 +29,222 @@
#include "hb-open-type.hh"
#include "hb-map.hh"
-#include "hb-priority-queue.hh"
-#include "hb-serialize.hh"
#include "hb-vector.hh"
+#include "graph/graph.hh"
+#include "graph/gsubgpos-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 lookup_size_t
{
- struct vertex_t
- {
- vertex_t () :
- distance (0),
- space (0),
- parents (),
- start (0),
- end (0),
- priority(0) {}
-
- void fini () {
- obj.fini ();
- parents.fini ();
- }
-
- hb_serialize_context_t::object_t obj;
- int64_t distance;
- int64_t space;
- hb_vector_t<unsigned> parents;
- unsigned start;
- unsigned end;
- unsigned 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.links.length;
- }
-
- void raise_priority ()
- {
- priority++;
- }
-
- 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), 0x7FFFFFFFFF);
- return (modified_distance << 22) | (0x003FFFFF & order);
- }
-
- int64_t distance_modifier () const
- {
- if (!priority) return 0;
- int64_t table_size = obj.tail - obj.head;
- return -(table_size - table_size / (1 << hb_min(priority, 16u)));
- }
- };
-
- struct overflow_record_t
- {
- unsigned parent;
- unsigned child;
- };
+ unsigned lookup_index;
+ size_t size;
+ unsigned num_subtables;
- /*
- * 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
- */
- graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects)
- : parents_invalid (true),
- distance_invalid (true),
- positions_invalid (true),
- successful (true)
+ static int cmp (const void* a, const void* b)
{
- 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;
- for (unsigned i = 0; i < v->obj.links.length; i++)
- // Fix indices to account for removed nil object.
- v->obj.links[i].objidx--;
- }
+ return cmp ((const lookup_size_t*) a,
+ (const lookup_size_t*) b);
}
- ~graph_t ()
+ static int cmp (const lookup_size_t* a, const lookup_size_t* b)
{
- vertices_.fini_deep ();
- }
-
- 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.
- */
- void serialize (hb_serialize_context_t* c) const
- {
- 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) return;
-
- memcpy (start, vertices_[i].obj.head, size);
-
- for (const auto& link : vertices_[i].obj.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 ();
- }
-
- /*
- * 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;
+ double subtables_per_byte_a = (double) a->num_subtables / (double) a->size;
+ double subtables_per_byte_b = (double) b->num_subtables / (double) b->size;
+ if (subtables_per_byte_a == subtables_per_byte_b) {
+ return b->lookup_index - a->lookup_index;
}
- 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.links) {
- removed_edges[link.objidx]++;
- if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
- queue.push (link.objidx);
- }
- }
-
- check_success (!queue.in_error ());
- check_success (!sorted_graph.in_error ());
- if (!check_success (new_id == -1))
- print_orphaned_nodes ();
-
- remap_all_obj_indices (id_map, &sorted_graph);
-
- hb_swap (vertices_, sorted_graph);
- sorted_graph.fini_deep ();
+ double cmp = subtables_per_byte_b - subtables_per_byte_a;
+ if (cmp < 0) return -1;
+ if (cmp > 0) return 1;
+ return 0;
}
+};
- /*
- * 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.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_deep ();
- }
-
- /*
- * 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++)
- {
- for (auto& l : vertices_[i].obj.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 (!roots.next (&next)) break;
-
- hb_set_t connected_roots;
- find_connected_nodes (next, roots, visited, connected_roots);
- isolate_subgraph (connected_roots);
-
- 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.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.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).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.links)
- {
- clone->obj.links.push (l);
- vertices_[l.objidx].parents.push (clone_idx);
- }
-
- check_success (!clone->obj.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.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.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);
+static inline
+bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+ // For each lookup this will check the size of subtables and split them as needed
+ // so that no subtable is at risk of overflowing. (where we support splitting for
+ // that subtable type).
+ //
+ // TODO(grieger): de-dup newly added nodes as necessary. Probably just want a full de-dup
+ // pass after this processing is done. Not super necessary as splits are
+ // only done where overflow is likely, so de-dup probably will get undone
+ // later anyways.
+ for (unsigned lookup_index : ext_context.lookups.keys ())
+ {
+ graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+ if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
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 (unsigned i = 0; i < parent.obj.links.length; i++)
- {
- auto& l = parent.obj.links[i];
- if (l.objidx != child_idx)
- continue;
-
- reassign_link (l, parent_idx, clone_idx);
- }
-
- return true;
}
- /*
- * Raises the sorting priority of all children.
- */
- void 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;
- for (unsigned i = 0; i < parent.links.length; i++)
- vertices_[parent.links[i].objidx].raise_priority ();
- }
-
- /*
- * 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--)
- {
- for (const auto& link : vertices_[parent_idx].obj.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 ();
- for (const auto& o : overflows)
- {
- 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.links.length,
- space_for (o.parent),
- o.child,
- child.incoming_edges (),
- child.obj.links.length,
- space_for (o.child));
- }
- }
-
- 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 (unsigned index)
- {
- auto& node = vertices_[index];
- num_roots_for_space_.push (1);
- num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
- node.space = num_roots_for_space_.length - 1;
- }
-
- 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:
+ return true;
+}
- /*
- * Returns the numbers of incoming edges that are 32bits wide.
- */
- unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
- {
- unsigned count = 0;
+/*
+ * Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
+ * to extension lookups.
+ */
+static inline
+bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+ // Simple Algorithm (v1, current):
+ // 1. Calculate how many bytes each non-extension lookup consumes.
+ // 2. Select up to 64k of those to remain as non-extension (greedy, highest subtables per byte first)
+ // 3. Promote the rest.
+ //
+ // Advanced Algorithm (v2, not implemented):
+ // 1. Perform connected component analysis using lookups as roots.
+ // 2. Compute size of each connected component.
+ // 3. Select up to 64k worth of connected components to remain as non-extensions.
+ // (greedy, highest subtables per byte first)
+ // 4. Promote the rest.
+
+ // TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
+ // TODO(garretrieger): also support extension promotion during iterative resolution phase, then
+ // we can use a less conservative threshold here.
+ // TODO(grieger): skip this for the 24 bit case.
+ if (!ext_context.lookups) return true;
+
+ hb_vector_t<lookup_size_t> lookup_sizes;
+ lookup_sizes.alloc (ext_context.lookups.get_population ());
+
+ for (unsigned lookup_index : ext_context.lookups.keys ())
+ {
+ const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
hb_set_t visited;
- for (unsigned p : vertices_[node_idx].parents)
- {
- if (visited.has (p)) continue;
- visited.add (p);
-
- for (const auto& l : vertices_[p].obj.links)
- {
- if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
- {
- count++;
- parents.add (p);
- }
- }
- }
- return count;
+ lookup_sizes.push (lookup_size_t {
+ lookup_index,
+ ext_context.graph.find_subgraph_size (lookup_index, visited),
+ lookup->number_of_subtables (),
+ });
}
- 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.links)
- {
- vertices_[l.objidx].parents.push (p);
- }
- }
+ lookup_sizes.qsort ();
- parents_invalid = false;
- }
+ size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
+ size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
+ size_t l3_l4_size = 0; // Lookups + SubTables
+ size_t l4_plus_size = 0; // SubTables + their descendants
- /*
- * compute the serialized start and end positions for each vertex.
- */
- void update_positions ()
+ // Start by assuming all lookups are using extension subtables, this size will be removed later
+ // if it's decided to not make a lookup extension.
+ for (auto p : lookup_sizes)
{
- 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;
+ unsigned subtables_size = p.num_subtables * 8;
+ l3_l4_size += subtables_size;
+ l4_plus_size += subtables_size;
}
- /*
- * Finds the distance to each object in the graph
- * from the initial node.
- */
- void update_distances ()
+ bool layers_full = false;
+ for (auto p : lookup_sizes)
{
- 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 fibonaacci 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);
+ const graph::Lookup* lookup = ext_context.lookups.get(p.lookup_index);
+ if (lookup->is_extension (ext_context.table_tag))
+ // already an extension so size is counted by the loop above.
+ continue;
- while (!queue.in_error () && !queue.is_empty ())
+ if (!layers_full)
{
- 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;
+ size_t lookup_size = ext_context.graph.vertices_[p.lookup_index].table_size ();
+ hb_set_t visited;
+ size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
+ size_t remaining_size = p.size - subtables_size - lookup_size;
- for (const auto& link : next.obj.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;
+ l2_l3_size += lookup_size;
+ l3_l4_size += lookup_size + subtables_size;
+ l3_l4_size -= p.num_subtables * 8;
+ l4_plus_size += subtables_size + remaining_size;
- if (child_distance < vertices_[link.objidx].distance)
- {
- vertices_[link.objidx].distance = child_distance;
- queue.insert (child_distance, link.objidx);
- }
- }
- }
+ if (l2_l3_size < (1 << 16)
+ && l3_l4_size < (1 << 16)
+ && l4_plus_size < (1 << 16)) continue; // this lookup fits within all layers groups
- check_success (!queue.in_error ());
- if (!check_success (queue.is_empty ()))
- {
- print_orphaned_nodes ();
- return;
+ layers_full = true;
}
- 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;
+ if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index))
+ return false;
}
- 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);
- }
- }
+ return true;
+}
- /*
- * 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);
- }
+static inline
+bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
+ graph_t& sorted_graph)
+{
+ unsigned space = 0;
+ hb_set_t roots_to_isolate;
- /*
- * 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)
+ for (int i = overflows.length - 1; i >= 0; i--)
{
- if (!id_map) return;
- for (unsigned i : subgraph)
- {
- for (unsigned j = 0; j < vertices_[i].obj.links.length; j++)
- {
- auto& link = vertices_[i].obj.links[j];
- if (!id_map.has (link.objidx)) continue;
- if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
+ const graph::overflow_record_t& r = overflows[i];
- reassign_link (link, i, id_map[link.objidx]);
- }
- }
- }
+ unsigned root;
+ unsigned overflow_space = sorted_graph.space_for (r.parent, &root);
+ if (!overflow_space) continue;
+ if (sorted_graph.num_roots_for_space (overflow_space) <= 1) continue;
- /*
- * 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 (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
- {
- auto& link = (*sorted_graph)[i].obj.links[j];
- link.objidx = id_map[link.objidx];
- }
+ if (!space) {
+ space = overflow_space;
}
- }
- 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);
+ if (space == overflow_space)
+ roots_to_isolate.add(root);
}
- 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);
- }
- }
+ if (!roots_to_isolate) return false;
- /*
- * 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 (visited.has (start_idx)) return;
- visited.add (start_idx);
-
- if (targets.has (start_idx))
- {
- targets.del (start_idx);
- connected.add (start_idx);
+ unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u);
+ if (roots_to_isolate.get_population () > maximum_to_move) {
+ // Only move at most half of the roots in a space at a time.
+ unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
+ while (extra--) {
+ uint32_t root = HB_SET_VALUE_INVALID;
+ roots_to_isolate.previous (&root);
+ roots_to_isolate.del (root);
}
-
- 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.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 bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
- graph_t& sorted_graph)
-{
- for (int i = overflows.length - 1; i >= 0; i--)
- {
- const graph_t::overflow_record_t& r = overflows[i];
- unsigned root = 0;
- unsigned space = sorted_graph.space_for (r.parent, &root);
- if (!space) continue;
- if (sorted_graph.num_roots_for_space (space) <= 1) continue;
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Overflow in space %d (%d roots). Moving %d roots to space %d.",
+ space,
+ sorted_graph.num_roots_for_space (space),
+ roots_to_isolate.get_population (),
+ sorted_graph.next_space ());
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Overflow in space %d moving subgraph %d to space %d.",
- space,
- root,
- sorted_graph.next_space ());
+ sorted_graph.isolate_subgraph (roots_to_isolate);
+ sorted_graph.move_to_new_space (roots_to_isolate);
- hb_set_t roots;
- roots.add (root);
- sorted_graph.isolate_subgraph (roots);
- for (unsigned new_root : roots)
- sorted_graph.move_to_new_space (new_root);
- return true;
- }
- return false;
+ return true;
}
-static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
- hb_set_t& priority_bumped_parents,
- graph_t& sorted_graph)
+static inline
+bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
+ hb_set_t& priority_bumped_parents,
+ graph_t& sorted_graph)
{
bool resolution_attempted = false;
// 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 ())
{
// The child object is shared, we may be able to eliminate the overflow
// by duplicating it.
- if (!sorted_graph.duplicate (r.parent, r.child)) continue;
+ if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
return true;
}
@@ -1093,16 +255,16 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o
// TODO(garretrieger): initially limiting this to leaf's since they can be
// moved closer with fewer consequences. However, this can
// likely can be used for non-leafs as well.
- // TODO(garretrieger): add a maximum priority, don't try to raise past this.
// TODO(garretrieger): also try lowering priority of the parent. Make it
// get placed further up in the ordering, closer to it's children.
// this is probably preferable if the total size of the parent object
// is < then the total size of the children (and the parent can be moved).
// Since in that case moving the parent will cause a smaller increase in
// the length of other offsets.
- sorted_graph.raise_childrens_priority (r.parent);
- priority_bumped_parents.add (r.parent);
- resolution_attempted = true;
+ if (sorted_graph.raise_childrens_priority (r.parent)) {
+ priority_bumped_parents.add (r.parent);
+ resolution_attempted = true;
+ }
continue;
}
@@ -1114,58 +276,66 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o
return resolution_attempted;
}
-/*
- * Attempts to modify the topological sorting of the provided object graph to
- * eliminate offset overflows in the links between objects of the graph. If a
- * non-overflowing ordering is found the updated graph is serialized it into the
- * provided serialization context.
- *
- * If necessary the structure of the graph may be modified in ways that do not
- * affect the functionality of the graph. For example shared objects may be
- * duplicated.
- *
- * For a detailed writeup describing how the algorithm operates see:
- * docs/repacker.md
- */
-inline void
-hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed,
- hb_tag_t table_tag,
- hb_serialize_context_t* c,
- unsigned max_rounds = 10) {
- // 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 ())
+inline bool
+hb_resolve_graph_overflows (hb_tag_t table_tag,
+ unsigned max_rounds ,
+ bool recalculate_extensions,
+ graph_t& sorted_graph /* IN/OUT */)
+{
+ sorted_graph.sort_shortest_distance ();
+ if (sorted_graph.in_error ())
{
- sorted_graph.serialize (c);
- return;
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state after initial sort.");
+ return false;
}
- sorted_graph.sort_shortest_distance ();
+ bool will_overflow = graph::will_overflow (sorted_graph);
+ if (!will_overflow)
+ return true;
+ graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
if ((table_tag == HB_OT_TAG_GPOS
|| table_tag == HB_OT_TAG_GSUB)
- && sorted_graph.will_overflow ())
+ && will_overflow)
{
+ if (recalculate_extensions)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
+ if (!_presplit_subtables_if_needed (ext_context)) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
+ return false;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
+ if (!_promote_extensions_if_needed (ext_context)) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
+ return false;
+ }
+ }
+
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
- if (sorted_graph.assign_32bit_spaces ())
+ if (sorted_graph.assign_spaces ())
sorted_graph.sort_shortest_distance ();
+ else
+ sorted_graph.sort_shortest_distance_if_needed ();
}
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)
- && round++ < max_rounds) {
+ && 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;
if (!_try_isolating_subgraphs (overflows, sorted_graph))
{
+ // Don't count space isolation towards round limit. Only increment
+ // round counter if space isolation made no changes.
+ round++;
if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
@@ -1178,17 +348,63 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac
if (sorted_graph.in_error ())
{
- c->err (HB_SERIALIZE_ERROR_OTHER);
- return;
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state.");
+ return false;
}
- if (sorted_graph.will_overflow ())
+ if (graph::will_overflow (sorted_graph))
{
- c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
- return;
+ return false;
}
- sorted_graph.serialize (c);
+
+ return true;
+}
+
+/*
+ * Attempts to modify the topological sorting of the provided object graph to
+ * eliminate offset overflows in the links between objects of the graph. If a
+ * non-overflowing ordering is found the updated graph is serialized it into the
+ * provided serialization context.
+ *
+ * If necessary the structure of the graph may be modified in ways that do not
+ * affect the functionality of the graph. For example shared objects may be
+ * duplicated.
+ *
+ * For a detailed writeup describing how the algorithm operates see:
+ * docs/repacker.md
+ */
+template<typename T>
+inline hb_blob_t*
+hb_resolve_overflows (const T& packed,
+ hb_tag_t table_tag,
+ unsigned max_rounds = 20,
+ bool recalculate_extensions = false) {
+ graph_t sorted_graph (packed);
+ if (sorted_graph.in_error ())
+ {
+ // Invalid graph definition.
+ return nullptr;
+ }
+
+ if (!sorted_graph.is_fully_connected ())
+ {
+ sorted_graph.print_orphaned_nodes ();
+ return nullptr;
+ }
+
+ if (sorted_graph.in_error ())
+ {
+ // Allocations failed somewhere
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Graph is in error, likely due to a memory allocation error.");
+ return nullptr;
+ }
+
+ if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
+ return nullptr;
+
+ return graph::serialize (sorted_graph);
}
#endif /* HB_REPACKER_HH */
diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh
index 2e536c7a8..bd3250e58 100644
--- a/src/hb-sanitize.hh
+++ b/src/hb-sanitize.hh
@@ -123,6 +123,7 @@ struct hb_sanitize_context_t :
hb_sanitize_context_t () :
start (nullptr), end (nullptr),
max_ops (0), max_subtables (0),
+ recursion_depth (0),
writable (false), edit_count (0),
blob (nullptr),
num_glyphs (65536),
@@ -197,14 +198,16 @@ struct hb_sanitize_context_t :
void start_processing ()
{
reset_object ();
- if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR)))
+ unsigned m;
+ if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m)))
this->max_ops = HB_SANITIZE_MAX_OPS_MAX;
else
- this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+ this->max_ops = hb_clamp (m,
(unsigned) HB_SANITIZE_MAX_OPS_MIN,
(unsigned) HB_SANITIZE_MAX_OPS_MAX);
this->edit_count = 0;
this->debug_depth = 0;
+ this->recursion_depth = 0;
DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
"start [%p..%p] (%lu bytes)",
@@ -250,8 +253,9 @@ struct hb_sanitize_context_t :
unsigned int a,
unsigned int b) const
{
- return !hb_unsigned_mul_overflows (a, b) &&
- this->check_range (base, a * b);
+ unsigned m;
+ return !hb_unsigned_mul_overflows (a, b, &m) &&
+ this->check_range (base, m);
}
template <typename T>
@@ -260,8 +264,9 @@ struct hb_sanitize_context_t :
unsigned int b,
unsigned int c) const
{
- return !hb_unsigned_mul_overflows (a, b) &&
- this->check_range (base, a * b, c);
+ unsigned m;
+ return !hb_unsigned_mul_overflows (a, b, &m) &&
+ this->check_range (base, m, c);
}
template <typename T>
@@ -278,6 +283,18 @@ struct hb_sanitize_context_t :
return this->check_range (base, a, b, hb_static_size (T));
}
+ bool check_start_recursion (int max_depth)
+ {
+ if (unlikely (recursion_depth >= max_depth)) return false;
+ return ++recursion_depth;
+ }
+
+ bool end_recursion (bool result)
+ {
+ recursion_depth--;
+ return result;
+ }
+
template <typename Type>
bool check_struct (const Type *obj) const
{ return likely (this->check_range (obj, obj->min_size)); }
@@ -389,6 +406,7 @@ struct hb_sanitize_context_t :
const char *start, *end;
mutable int max_ops, max_subtables;
private:
+ int recursion_depth;
bool writable;
unsigned int edit_count;
hb_blob_t *blob;
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
index 57689916f..d5573281f 100644
--- a/src/hb-serialize.hh
+++ b/src/hb-serialize.hh
@@ -36,6 +36,9 @@
#include "hb-map.hh"
#include "hb-pool.hh"
+#ifdef HB_EXPERIMENTAL_API
+#include "hb-subset-repacker.h"
+#endif
/*
* Serialize
@@ -65,35 +68,97 @@ struct hb_serialize_context_t
struct object_t
{
- void fini () { links.fini (); }
+ void fini () {
+ real_links.fini ();
+ virtual_links.fini ();
+ }
+
+ object_t () = default;
+
+#ifdef HB_EXPERIMENTAL_API
+ object_t (const hb_object_t &o)
+ {
+ head = o.head;
+ tail = o.tail;
+ next = nullptr;
+ real_links.alloc (o.num_real_links);
+ for (unsigned i = 0 ; i < o.num_real_links; i++)
+ real_links.push (o.real_links[i]);
+
+ virtual_links.alloc (o.num_virtual_links);
+ for (unsigned i = 0; i < o.num_virtual_links; i++)
+ virtual_links.push (o.virtual_links[i]);
+ }
+#endif
+
+ friend void swap (object_t& a, object_t& b)
+ {
+ hb_swap (a.head, b.head);
+ hb_swap (a.tail, b.tail);
+ hb_swap (a.next, b.next);
+ hb_swap (a.real_links, b.real_links);
+ hb_swap (a.virtual_links, b.virtual_links);
+ }
bool operator == (const object_t &o) const
{
+ // Virtual links aren't considered for equality since they don't affect the functionality
+ // of the object.
return (tail - head == o.tail - o.head)
- && (links.length == o.links.length)
+ && (real_links.length == o.real_links.length)
&& 0 == hb_memcmp (head, o.head, tail - head)
- && links.as_bytes () == o.links.as_bytes ();
+ && real_links.as_bytes () == o.real_links.as_bytes ();
}
uint32_t hash () const
{
+ // Virtual links aren't considered for equality since they don't affect the functionality
+ // of the object.
return hb_bytes_t (head, tail - head).hash () ^
- links.as_bytes ().hash ();
+ real_links.as_bytes ().hash ();
}
struct link_t
{
unsigned width: 3;
- bool is_signed: 1;
+ unsigned is_signed: 1;
unsigned whence: 2;
- unsigned position: 28;
- unsigned bias;
+ unsigned bias : 26;
+ unsigned position;
objidx_t objidx;
+
+ link_t () = default;
+
+#ifdef HB_EXPERIMENTAL_API
+ link_t (const hb_link_t &o)
+ {
+ width = o.width;
+ is_signed = 0;
+ whence = 0;
+ position = o.position;
+ bias = 0;
+ objidx = o.objidx;
+ }
+#endif
+
+ HB_INTERNAL static int cmp (const void* a, const void* b)
+ {
+ int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position;
+ if (cmp) return cmp;
+
+ return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx;
+ }
};
char *head;
char *tail;
- hb_vector_t<link_t> links;
+ hb_vector_t<link_t> real_links;
+ hb_vector_t<link_t> virtual_links;
object_t *next;
+
+ auto all_links () const HB_AUTO_RETURN
+ (( hb_concat (this->real_links, this->virtual_links) ));
+ auto all_links_writer () HB_AUTO_RETURN
+ (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
};
struct snapshot_t
@@ -101,12 +166,14 @@ struct hb_serialize_context_t
char *head;
char *tail;
object_t *current; // Just for sanity check
- unsigned num_links;
+ unsigned num_real_links;
+ unsigned num_virtual_links;
hb_serialize_error_t errors;
};
snapshot_t snapshot ()
- { return snapshot_t { head, tail, current, current->links.length, errors }; }
+ { return snapshot_t {
+ head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
hb_serialize_context_t (void *start_, unsigned int size) :
start ((char *) start_),
@@ -127,7 +194,6 @@ struct hb_serialize_context_t
current = current->next;
_->fini ();
}
- object_pool.fini ();
}
bool in_error () const { return bool (errors); }
@@ -157,6 +223,7 @@ struct hb_serialize_context_t
this->errors = HB_SERIALIZE_ERROR_NONE;
this->head = this->start;
this->tail = this->end;
+ this->zerocopy = nullptr;
this->debug_depth = 0;
fini ();
@@ -256,15 +323,16 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return;
- if (unlikely (in_error())) return;
+ if (unlikely (in_error() && !only_overflow ())) return;
current = current->next;
- revert (obj->head, obj->tail);
+ revert (zerocopy ? zerocopy : obj->head, obj->tail);
+ zerocopy = nullptr;
obj->fini ();
object_pool.release (obj);
}
- /* Set share to false when an object is unlikely sharable with others
+ /* Set share to false when an object is unlikely shareable with others
* so not worth an attempt, or a contiguous table is serialized as
* multiple consecutive objects in the reverse order so can't be shared.
*/
@@ -277,28 +345,38 @@ struct hb_serialize_context_t
current = current->next;
obj->tail = head;
obj->next = nullptr;
+ assert (obj->head <= obj->tail);
unsigned len = obj->tail - obj->head;
- head = obj->head; /* Rewind head. */
+ head = zerocopy ? zerocopy : obj->head; /* Rewind head. */
+ bool was_zerocopy = zerocopy;
+ zerocopy = nullptr;
if (!len)
{
- assert (!obj->links.length);
+ assert (!obj->real_links.length);
+ assert (!obj->virtual_links.length);
return 0;
}
objidx_t objidx;
+ uint32_t hash = 0;
if (share)
{
- objidx = packed_map.get (obj);
+ hash = hb_hash (obj);
+ objidx = packed_map.get_with_hash (obj, hash);
if (objidx)
{
+ merge_virtual_links (obj, objidx);
obj->fini ();
return objidx;
}
}
tail -= len;
- memmove (tail, obj->head, len);
+ if (was_zerocopy)
+ assert (tail == obj->head);
+ else
+ memmove (tail, obj->head, len);
obj->head = tail;
obj->tail = tail + len;
@@ -316,7 +394,7 @@ struct hb_serialize_context_t
objidx = packed.length - 1;
- if (share) packed_map.set (obj, objidx);
+ if (share) packed_map.set_with_hash (obj, hash, objidx);
propagate_error (packed_map);
return objidx;
@@ -327,7 +405,8 @@ struct hb_serialize_context_t
// Overflows that happened after the snapshot will be erased by the revert.
if (unlikely (in_error () && !only_overflow ())) return;
assert (snap.current == current);
- current->links.shrink (snap.num_links);
+ current->real_links.shrink (snap.num_real_links);
+ current->virtual_links.shrink (snap.num_virtual_links);
errors = snap.errors;
revert (snap.head, snap.tail);
}
@@ -363,7 +442,7 @@ struct hb_serialize_context_t
// Adding a virtual link from object a to object b will ensure that object b is always packed after
// object a in the final serialized order.
//
- // This is useful in certain situtations where there needs to be a specific ordering in the
+ // This is useful in certain situations where there needs to be a specific ordering in the
// final serialization. Such as when platform bugs require certain orderings, or to provide
// guidance to the repacker for better offset overflow resolution.
void add_virtual_link (objidx_t objidx)
@@ -375,8 +454,8 @@ struct hb_serialize_context_t
assert (current);
- auto& link = *current->links.push ();
- if (current->links.in_error ())
+ auto& link = *current->virtual_links.push ();
+ if (current->virtual_links.in_error ())
err (HB_SERIALIZE_ERROR_OTHER);
link.width = 0;
@@ -400,8 +479,8 @@ struct hb_serialize_context_t
assert (current);
assert (current->head <= (const char *) &ofs);
- auto& link = *current->links.push ();
- if (current->links.in_error ())
+ auto& link = *current->real_links.push ();
+ if (current->real_links.in_error ())
err (HB_SERIALIZE_ERROR_OTHER);
link.width = sizeof (T);
@@ -440,10 +519,8 @@ struct hb_serialize_context_t
assert (packed.length > 1);
for (const object_t* parent : ++hb_iter (packed))
- for (const object_t::link_t &link : parent->links)
+ for (const object_t::link_t &link : parent->real_links)
{
- if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets
-
const object_t* child = packed[link.objidx];
if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
unsigned offset = 0;
@@ -494,15 +571,33 @@ struct hb_serialize_context_t
{ return reinterpret_cast<Type *> (this->head); }
template <typename Type>
Type *start_embed (const Type &obj) const
- { return start_embed (hb_addressof (obj)); }
+ { return start_embed (std::addressof (obj)); }
bool err (hb_serialize_error_t err_type)
{
return !bool ((errors = (errors | err_type)));
}
+ bool start_zerocopy (size_t size)
+ {
+ if (unlikely (in_error ())) return false;
+
+ if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
+ {
+ err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
+ return false;
+ }
+
+ assert (!this->zerocopy);
+ this->zerocopy = this->head;
+
+ assert (this->current->head == this->head);
+ this->current->head = this->current->tail = this->head = this->tail - size;
+ return true;
+ }
+
template <typename Type>
- Type *allocate_size (size_t size)
+ Type *allocate_size (size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -511,7 +606,8 @@ struct hb_serialize_context_t
err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
return nullptr;
}
- hb_memset (this->head, 0, size);
+ if (clear)
+ hb_memset (this->head, 0, size);
char *ret = this->head;
this->head += size;
return reinterpret_cast<Type *> (ret);
@@ -525,14 +621,14 @@ struct hb_serialize_context_t
Type *embed (const Type *obj)
{
unsigned int size = obj->get_size ();
- Type *ret = this->allocate_size<Type> (size);
+ Type *ret = this->allocate_size<Type> (size, false);
if (unlikely (!ret)) return nullptr;
- memcpy (ret, obj, size);
+ hb_memcpy (ret, obj, size);
return ret;
}
template <typename Type>
Type *embed (const Type &obj)
- { return embed (hb_addressof (obj)); }
+ { return embed (std::addressof (obj)); }
template <typename Type, typename ...Ts> auto
_copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
@@ -548,7 +644,7 @@ struct hb_serialize_context_t
}
/* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
- * instead of memcpy(). */
+ * instead of hb_memcpy(). */
template <typename Type, typename ...Ts>
Type *copy (const Type &src, Ts&&... ds)
{ return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); }
@@ -566,7 +662,7 @@ struct hb_serialize_context_t
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
template <typename Type>
- Type *extend_size (Type *obj, size_t size)
+ Type *extend_size (Type *obj, size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -574,24 +670,24 @@ struct hb_serialize_context_t
assert ((char *) obj <= this->head);
assert ((size_t) (this->head - (char *) obj) <= size);
if (unlikely (((char *) obj + size < (char *) obj) ||
- !this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+ !this->allocate_size<Type> (((char *) obj) + size - this->head, clear))) return nullptr;
return reinterpret_cast<Type *> (obj);
}
template <typename Type>
- Type *extend_size (Type &obj, size_t size)
- { return extend_size (hb_addressof (obj), size); }
+ Type *extend_size (Type &obj, size_t size, bool clear = true)
+ { return extend_size (std::addressof (obj), size, clear); }
template <typename Type>
Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
template <typename Type>
- Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); }
+ Type *extend_min (Type &obj) { return extend_min (std::addressof (obj)); }
template <typename Type, typename ...Ts>
Type *extend (Type *obj, Ts&&... ds)
{ return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); }
template <typename Type, typename ...Ts>
Type *extend (Type &obj, Ts&&... ds)
- { return extend (hb_addressof (obj), std::forward<Ts> (ds)...); }
+ { return extend (std::addressof (obj), std::forward<Ts> (ds)...); }
/* Output routines. */
hb_bytes_t copy_bytes () const
@@ -608,8 +704,8 @@ struct hb_serialize_context_t
char *p = (char *) hb_malloc (len);
if (unlikely (!p)) return hb_bytes_t ();
- memcpy (p, this->start, this->head - this->start);
- memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
+ hb_memcpy (p, this->start, this->head - this->start);
+ hb_memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
return hb_bytes_t (p, len);
}
template <typename Type>
@@ -635,13 +731,20 @@ struct hb_serialize_context_t
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
}
- public: /* TODO Make private. */
- char *start, *head, *tail, *end;
+ public:
+ char *start, *head, *tail, *end, *zerocopy;
unsigned int debug_depth;
hb_serialize_error_t errors;
private:
+ void merge_virtual_links (const object_t* from, objidx_t to_idx) {
+ object_t* to = packed[to_idx];
+ for (const auto& l : from->virtual_links) {
+ to->virtual_links.push (l);
+ }
+ }
+
/* Object memory pool. */
hb_pool_t<object_t> object_pool;
@@ -652,7 +755,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, nullptr, 0> packed_map;
+ hb_hashmap_t<const object_t *, objidx_t> packed_map;
};
#endif /* HB_SERIALIZE_HH */
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index 7d4979b73..e8409111f 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -28,9 +28,10 @@
#define HB_SET_DIGEST_HH
#include "hb.hh"
+#include "hb-machinery.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 +41,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;
@@ -63,6 +76,8 @@ struct hb_set_digest_lowest_bits_t
void init () { mask = 0; }
+ void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
+
void add (hb_codepoint_t g) { mask |= mask_for (g); }
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
@@ -83,7 +98,7 @@ struct hb_set_digest_lowest_bits_t
for (unsigned int i = 0; i < count; i++)
{
add (*array);
- array = (const T *) (stride + (const char *) array);
+ array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
}
}
template <typename T>
@@ -91,18 +106,17 @@ struct hb_set_digest_lowest_bits_t
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
- for (unsigned int i = 0; i < count; i++)
- {
- add (*array);
- array = (const T *) (stride + (const char *) array);
- }
+ add_array (array, count, stride);
return true;
}
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+ bool may_have (const hb_set_digest_bits_pattern_t &o) const
+ { return mask & o.mask; }
+
bool may_have (hb_codepoint_t g) const
- { return !!(mask & mask_for (g)); }
+ { return mask & mask_for (g); }
private:
@@ -120,6 +134,12 @@ struct hb_set_digest_combiner_t
tail.init ();
}
+ void add (const hb_set_digest_combiner_t &o)
+ {
+ head.add (o.head);
+ tail.add (o.tail);
+ }
+
void add (hb_codepoint_t g)
{
head.add (g);
@@ -128,9 +148,8 @@ struct hb_set_digest_combiner_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
- head.add_range (a, b);
- tail.add_range (a, b);
- return true;
+ return head.add_range (a, b) &&
+ tail.add_range (a, b);
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -143,13 +162,17 @@ struct hb_set_digest_combiner_t
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
- head.add_sorted_array (array, count, stride);
- tail.add_sorted_array (array, count, stride);
- return true;
+ return head.add_sorted_array (array, count, stride) &&
+ tail.add_sorted_array (array, count, stride);
}
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+ bool may_have (const hb_set_digest_combiner_t &o) const
+ {
+ return head.may_have (o.head) && tail.may_have (o.tail);
+ }
+
bool may_have (hb_codepoint_t g) const
{
return head.may_have (g) && tail.may_have (g);
@@ -171,11 +194,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/src/hb-set.cc b/src/hb-set.cc
index 204dbb564..0270b2199 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -40,7 +40,7 @@
/**
- * hb_set_create: (Xconstructor)
+ * hb_set_create:
*
* Creates a new, initially empty set.
*
@@ -56,8 +56,6 @@ hb_set_create ()
if (!(set = hb_object_create<hb_set_t> ()))
return hb_set_get_empty ();
- set->init_shallow ();
-
return set;
}
@@ -107,8 +105,6 @@ hb_set_destroy (hb_set_t *set)
{
if (!hb_object_destroy (set)) return;
- set->fini_shallow ();
-
hb_free (set);
}
@@ -122,7 +118,7 @@ hb_set_destroy (hb_set_t *set)
*
* Attaches a user-data key/data pair to the specified set.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -149,7 +145,7 @@ hb_set_set_user_data (hb_set_t *set,
* Since: 0.9.2
**/
void *
-hb_set_get_user_data (hb_set_t *set,
+hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (set, key);
@@ -162,7 +158,7 @@ hb_set_get_user_data (hb_set_t *set,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
*
* Since: 0.9.2
**/
@@ -186,6 +182,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;
}
@@ -211,7 +208,7 @@ hb_set_clear (hb_set_t *set)
*
* Tests whether a set is empty (contains no elements).
*
- * Return value: %true if @set is empty
+ * Return value: `true` if @set is empty
*
* Since: 0.9.7
**/
@@ -228,7 +225,7 @@ hb_set_is_empty (const hb_set_t *set)
*
* Tests whether @codepoint belongs to @set.
*
- * Return value: %true if @codepoint is in @set, %false otherwise
+ * Return value: `true` if @codepoint is in @set, `false` otherwise
*
* Since: 0.9.2
**/
@@ -257,6 +254,29 @@ hb_set_add (hb_set_t *set,
}
/**
+ * hb_set_add_sorted_array:
+ * @set: A set
+ * @sorted_codepoints: (array length=num_codepoints): Array of codepoints to add
+ * @num_codepoints: Length of @sorted_codepoints
+ *
+ * Adds @num_codepoints codepoints to a set at once.
+ * The codepoints array must be in increasing order,
+ * with size at least @num_codepoints.
+ *
+ * Since: 4.1.0
+ */
+HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t *set,
+ const hb_codepoint_t *sorted_codepoints,
+ unsigned int num_codepoints)
+{
+ /* Immutible-safe. */
+ set->add_sorted_array (sorted_codepoints,
+ num_codepoints,
+ sizeof(hb_codepoint_t));
+}
+
+/**
* hb_set_add_range:
* @set: A set
* @first: The first element to add to @set
@@ -324,7 +344,7 @@ hb_set_del_range (hb_set_t *set,
* Tests whether @set and @other are equal (contain the same
* elements).
*
- * Return value: %true if the two sets are equal, %false otherwise.
+ * Return value: `true` if the two sets are equal, `false` otherwise.
*
* Since: 0.9.7
**/
@@ -336,13 +356,30 @@ 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
*
* Tests whether @set is a subset of @larger_set.
*
- * Return value: %true if the @set is a subset of (or equal to) @larger_set, %false otherwise.
+ * Return value: `true` if the @set is a subset of (or equal to) @larger_set, `false` otherwise.
*
* Since: 1.8.1
**/
@@ -512,7 +549,7 @@ hb_set_get_max (const hb_set_t *set)
*
* Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next value, %false otherwise
+ * Return value: `true` if there was a next value, `false` otherwise
*
* Since: 0.9.2
**/
@@ -533,7 +570,7 @@ hb_set_next (const hb_set_t *set,
*
* Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous value, %false otherwise
+ * Return value: `true` if there was a previous value, `false` otherwise
*
* Since: 1.8.0
**/
@@ -556,7 +593,7 @@ hb_set_previous (const hb_set_t *set,
*
* Set @last to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next range, %false otherwise
+ * Return value: `true` if there was a next range, `false` otherwise
*
* Since: 0.9.7
**/
@@ -580,7 +617,7 @@ hb_set_next_range (const hb_set_t *set,
*
* Set @first to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous range, %false otherwise
+ * Return value: `true` if there was a previous range, `false` otherwise
*
* Since: 1.8.0
**/
@@ -591,3 +628,28 @@ hb_set_previous_range (const hb_set_t *set,
{
return set->previous_range (first, last);
}
+
+/**
+ * hb_set_next_many:
+ * @set: A set
+ * @codepoint: Outputting codepoints starting after this one.
+ * Use #HB_SET_VALUE_INVALID to get started.
+ * @out: (array length=size): An array of codepoints to write to.
+ * @size: The maximum number of codepoints to write out.
+ *
+ * Finds the next element in @set that is greater than @codepoint. Writes out
+ * codepoints to @out, until either the set runs out of elements, or @size
+ * codepoints are written, whichever comes first.
+ *
+ * Return value: the number of values written.
+ *
+ * Since: 4.2.0
+ **/
+unsigned int
+hb_set_next_many (const hb_set_t *set,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *out,
+ unsigned int size)
+{
+ return set->next_many (codepoint, out, size);
+}
diff --git a/src/hb-set.h b/src/hb-set.h
index 423225bf9..93636ab5d 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -77,7 +77,7 @@ hb_set_set_user_data (hb_set_t *set,
hb_bool_t replace);
HB_EXTERN void *
-hb_set_get_user_data (hb_set_t *set,
+hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key);
@@ -111,6 +111,11 @@ hb_set_add_range (hb_set_t *set,
hb_codepoint_t last);
HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t *set,
+ const hb_codepoint_t *sorted_codepoints,
+ unsigned int num_codepoints);
+
+HB_EXTERN void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint);
@@ -123,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);
@@ -180,6 +188,12 @@ hb_set_previous_range (const hb_set_t *set,
hb_codepoint_t *first,
hb_codepoint_t *last);
+/* Pass HB_SET_VALUE_INVALID in to get started. */
+HB_EXTERN unsigned int
+hb_set_next_many (const hb_set_t *set,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *out,
+ unsigned int size);
HB_END_DECLS
diff --git a/src/hb-set.hh b/src/hb-set.hh
index 884142718..f958a081f 100644
--- a/src/hb-set.hh
+++ b/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,23 +53,21 @@ 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);
}
- void init_shallow () { s.init (); }
void init ()
{
hb_object_init (this);
- init_shallow ();
+ s.init ();
}
- void fini_shallow () { s.fini (); }
void fini ()
{
hb_object_fini (this);
- fini_shallow ();
+ s.fini ();
}
explicit operator bool () const { return !is_empty (); }
@@ -77,10 +75,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); }
@@ -105,10 +105,9 @@ struct hb_sparseset_t
bool get (hb_codepoint_t g) const { return s.get (g); }
/* Has interface. */
- static constexpr bool SENTINEL = false;
- typedef bool value_t;
- value_t operator [] (hb_codepoint_t k) const { return get (k); }
- bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k]; }
+
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@@ -124,6 +123,8 @@ struct hb_sparseset_t
void set (const hb_sparseset_t &other) { s.set (other.s); }
bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); }
+ bool operator == (const hb_set_t &other) const { return is_equal (other); }
+ bool operator != (const hb_set_t &other) const { return !is_equal (other); }
bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); }
@@ -138,6 +139,8 @@ struct hb_sparseset_t
{ return s.next_range (first, last); }
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{ return s.previous_range (first, last); }
+ unsigned int next_many (hb_codepoint_t codepoint, hb_codepoint_t *out, unsigned int size) const
+ { return s.next_many (codepoint, out, size); }
unsigned int get_population () const { return s.get_population (); }
hb_codepoint_t get_min () const { return s.get_min (); }
@@ -155,15 +158,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& o) = default;
- hb_set_t& operator= (const hb_set_t& other) = default;
- hb_set_t& operator= (hb_set_t&& other) = 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/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 66332165c..cabcbd4e7 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -31,6 +31,8 @@
#include "hb-buffer.hh"
+#ifndef HB_NO_SHAPER
+
/**
* SECTION:hb-shape-plan
* @title: hb-shape-plan
@@ -74,7 +76,7 @@ hb_shape_plan_key_t::init (bool copy,
this->user_features = copy ? features : user_features;
if (copy && num_user_features)
{
- memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+ hb_memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
/* Make start/end uniform to easier catch bugs. */
for (unsigned int i = 0; i < num_user_features; i++)
{
@@ -117,7 +119,7 @@ hb_shape_plan_key_t::init (bool copy,
}
else
{
- const hb_shaper_entry_t *shapers = _hb_shapers_get ();
+ const HB_UNUSED hb_shaper_entry_t *shapers = _hb_shapers_get ();
for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
if (false)
;
@@ -170,7 +172,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 +200,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 +233,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;
@@ -317,10 +320,6 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
{
if (!hb_object_destroy (shape_plan)) return;
-#ifndef HB_NO_OT_SHAPE
- shape_plan->ot.fini ();
-#endif
- shape_plan->key.fini ();
hb_free (shape_plan);
}
@@ -334,7 +333,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
*
* Attaches a user-data key/data pair to the given shaping plan.
*
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
*
* Since: 0.9.7
**/
@@ -361,8 +360,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
* Since: 0.9.7
**/
void *
-hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
- hb_user_data_key_t *key)
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (shape_plan, key);
}
@@ -439,7 +438,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t *shape_plan,
* Executes the given shaping plan on the specified buffer, using
* the given @font and @features.
*
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
*
* Since: 0.9.7
**/
@@ -577,3 +576,6 @@ retry:
return hb_shape_plan_reference (shape_plan);
}
+
+
+#endif
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index fc7c04189..aaf5cf9c4 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -102,8 +102,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_bool_t replace);
HB_EXTERN void *
-hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
- hb_user_data_key_t *key);
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key);
HB_EXTERN hb_bool_t
diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh
index 8cb4ddb92..6fc73939b 100644
--- a/src/hb-shape-plan.hh
+++ b/src/hb-shape-plan.hh
@@ -55,7 +55,7 @@ struct hb_shape_plan_key_t
unsigned int num_coords,
const char * const *shaper_list);
- HB_INTERNAL void fini () { hb_free ((void *) user_features); }
+ HB_INTERNAL void fini () { hb_free ((void *) user_features); user_features = nullptr; }
HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
@@ -64,6 +64,7 @@ struct hb_shape_plan_key_t
struct hb_shape_plan_t
{
+ ~hb_shape_plan_t () { key.fini (); }
hb_object_header_t header;
hb_face_t *face_unsafe; /* We don't carry a reference to face. */
hb_shape_plan_key_t key;
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index c1f619c81..7b5bf2c5e 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -35,6 +35,8 @@
#include "hb-machinery.hh"
+#ifndef HB_NO_SHAPER
+
/**
* SECTION:hb-shape
* @title: hb-shape
@@ -50,7 +52,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 +75,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;
@@ -106,12 +108,12 @@ hb_shape_list_shapers ()
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
* @features: (array length=num_features) (nullable): an array of user
- * specified #hb_feature_t or %NULL
+ * specified #hb_feature_t or `NULL`
* @num_features: the length of @features array
- * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated
- * array of shapers to use or %NULL
+ * @shaper_list: (array zero-terminated=1) (nullable): a `NULL`-terminated
+ * array of shapers to use or `NULL`
*
- * See hb_shape() for details. If @shaper_list is not %NULL, the specified
+ * See hb_shape() for details. If @shaper_list is not `NULL`, the specified
* shapers will be used in the given order, otherwise the default shapers list
* will be used.
*
@@ -126,13 +128,45 @@ 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)
+ {
+ text_buffer = hb_buffer_create ();
+ hb_buffer_append (text_buffer, buffer, 0, -1);
+ }
+
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
features, num_features,
font->coords, font->num_coords,
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->successful && !buffer->shaping_failed
+ && text_buffer->successful
+ && !buffer->verify (text_buffer,
+ font,
+ features,
+ num_features,
+ shaper_list))
+ res = false;
+ hb_buffer_destroy (text_buffer);
+ }
+
+ buffer->leave ();
+
return res;
}
@@ -141,11 +175,11 @@ hb_shape_full (hb_font_t *font,
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
* @features: (array length=num_features) (nullable): an array of user
- * specified #hb_feature_t or %NULL
+ * specified #hb_feature_t or `NULL`
* @num_features: the length of @features array
*
* Shapes @buffer using @font turning its Unicode characters content to
- * positioned glyphs. If @features is not %NULL, it will be used to control the
+ * positioned glyphs. If @features is not `NULL`, it will be used to control the
* features applied during shaping. If two @features have the same tag but
* overlapping ranges the value of the feature with the higher index takes
* precedence.
@@ -160,3 +194,6 @@ hb_shape (hb_font_t *font,
{
hb_shape_full (font, buffer, features, num_features, nullptr);
}
+
+
+#endif
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index a11ed83af..c4885cda9 100644
--- a/src/hb-shaper.cc
+++ b/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));
+ hb_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_CONST (_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/src/hb-static.cc b/src/hb-static.cc
index ec4b24147..eac50754c 100644
--- a/src/hb-static.cc
+++ b/src/hb-static.cc
@@ -33,6 +33,8 @@
#include "hb-aat-layout-feat-table.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
+#include "hb-ot-color-colr-table.hh"
+#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
@@ -45,27 +47,56 @@ uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
-DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00};
+DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x01};
+DEFINE_NULL_NAMESPACE_BYTES (OT, ClipRecord) = {0x01};
DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00};
DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF};
-/* Hand-coded because Lookup is a template. Sad. */
-const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
+DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
+/* hb_map_t */
+
+const hb_codepoint_t minus_1 = -1;
/* hb_face_t */
+#ifndef HB_NO_BEYOND_64K
+static inline unsigned
+load_num_glyphs_from_loca (const hb_face_t *face)
+{
+ unsigned ret = 0;
+
+ unsigned indexToLocFormat = face->table.head->indexToLocFormat;
+
+ if (indexToLocFormat <= 1)
+ {
+ bool short_offset = 0 == indexToLocFormat;
+ hb_blob_t *loca_blob = face->table.loca.get_blob ();
+ ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1;
+ }
+
+ return ret;
+}
+#endif
+
+static inline unsigned
+load_num_glyphs_from_maxp (const hb_face_t *face)
+{
+ return face->table.maxp->get_num_glyphs ();
+}
+
unsigned int
hb_face_t::load_num_glyphs () const
{
- hb_sanitize_context_t c = hb_sanitize_context_t ();
- c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
- hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
- const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
-
- unsigned int ret = maxp_table->get_num_glyphs ();
- num_glyphs.set_relaxed (ret);
- hb_blob_destroy (maxp_blob);
+ unsigned ret = 0;
+
+#ifndef HB_NO_BEYOND_64K
+ ret = hb_max (ret, load_num_glyphs_from_loca (this));
+#endif
+
+ ret = hb_max (ret, load_num_glyphs_from_maxp (this));
+
+ num_glyphs = ret;
return ret;
}
@@ -73,7 +104,7 @@ unsigned int
hb_face_t::load_upem () const
{
unsigned int ret = table.head->get_upem ();
- upem.set_relaxed (ret);
+ upem = ret;
return ret;
}
diff --git a/src/hb-style.cc b/src/hb-style.cc
index f1b44cea5..c7d7d713c 100644
--- a/src/hb-style.cc
+++ b/src/hb-style.cc
@@ -46,15 +46,14 @@
static inline float
_hb_angle_to_ratio (float a)
{
- return tanf (a * float (M_PI / 180.));
+ return tanf (a * float (-M_PI / 180.));
}
-#if 0
+
static inline float
_hb_ratio_to_angle (float r)
{
- return atanf (r) * float (180. / M_PI);
+ return atanf (r) * float (-180. / M_PI);
}
-#endif
/**
* hb_style_get_value:
@@ -109,7 +108,14 @@ hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag)
: 12.f;
}
case HB_STYLE_TAG_SLANT_ANGLE:
- return face->table.post->table->italicAngle.to_float ();
+ {
+ float angle = face->table.post->table->italicAngle.to_float ();
+
+ if (font->slant)
+ angle = _hb_ratio_to_angle (font->slant + _hb_angle_to_ratio (angle));
+
+ return angle;
+ }
case HB_STYLE_TAG_WIDTH:
return face->table.OS2->has_data ()
? face->table.OS2->get_width ()
diff --git a/src/hb-style.h b/src/hb-style.h
index 30a6f2b87..d17d2daa5 100644
--- a/src/hb-style.h
+++ b/src/hb-style.h
@@ -43,8 +43,10 @@ HB_BEGIN_DECLS
* @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values
* must be greater than -90 and less than +90. Values can be interpreted as
* the angle, in counter-clockwise degrees, of oblique slant from whatever the
- * designer considers to be upright for that font design.
+ * designer considers to be upright for that font design. Typical right-leaning
+ * Italic fonts have a negative slant angle (typically around -12)
* @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio.
+ * Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2)
* @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider.
* Non-zero. Values can be interpreted as a percentage of whatever the font
* designer considers “normal width” for that font design.
diff --git a/src/hb-subset-accelerator.hh b/src/hb-subset-accelerator.hh
new file mode 100644
index 000000000..63ae6d77e
--- /dev/null
+++ b/src/hb-subset-accelerator.hh
@@ -0,0 +1,121 @@
+/*
+ * 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 HB_SUBSET_ACCELERATOR_HH
+#define HB_SUBSET_ACCELERATOR_HH
+
+
+#include "hb.hh"
+
+#include "hb-map.hh"
+#include "hb-multimap.hh"
+#include "hb-set.hh"
+
+extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
+
+namespace CFF {
+struct cff_subset_accelerator_t;
+}
+
+namespace OT {
+struct SubtableUnicodesCache;
+};
+
+struct hb_subset_accelerator_t
+{
+ static hb_user_data_key_t* user_data_key()
+ {
+ return &_hb_subset_accelerator_user_data_key;
+ }
+
+ static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
+ const hb_multimap_t gid_to_unicodes_,
+ const hb_set_t& unicodes_,
+ bool has_seac_) {
+ hb_subset_accelerator_t* accel =
+ (hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
+ new (accel) hb_subset_accelerator_t (unicode_to_gid_, gid_to_unicodes_, unicodes_);
+ accel->has_seac = has_seac_;
+ return accel;
+ }
+
+ static void destroy(void* value) {
+ if (!value) return;
+
+ hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
+
+ if (accel->cff_accelerator && accel->destroy_cff_accelerator)
+ accel->destroy_cff_accelerator ((void*) accel->cff_accelerator);
+
+ if (accel->cmap_cache && accel->destroy_cmap_cache)
+ accel->destroy_cmap_cache ((void*) accel->cmap_cache);
+
+ accel->~hb_subset_accelerator_t ();
+ hb_free (accel);
+ }
+
+ hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_,
+ const hb_multimap_t& gid_to_unicodes_,
+ const hb_set_t& unicodes_)
+ : unicode_to_gid(unicode_to_gid_), gid_to_unicodes (gid_to_unicodes_), unicodes(unicodes_),
+ cmap_cache(nullptr), destroy_cmap_cache(nullptr),
+ has_seac(false), cff_accelerator(nullptr), destroy_cff_accelerator(nullptr)
+ { sanitized_table_cache_lock.init (); }
+
+ ~hb_subset_accelerator_t ()
+ { sanitized_table_cache_lock.fini (); }
+
+ // Generic
+
+ mutable hb_mutex_t sanitized_table_cache_lock;
+ mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
+
+ const hb_map_t unicode_to_gid;
+ const hb_multimap_t gid_to_unicodes;
+ const hb_set_t unicodes;
+
+ // cmap
+ const OT::SubtableUnicodesCache* cmap_cache;
+ hb_destroy_func_t destroy_cmap_cache;
+
+ // CFF
+ bool has_seac;
+ const CFF::cff_subset_accelerator_t* cff_accelerator;
+ hb_destroy_func_t destroy_cff_accelerator;
+
+ // TODO(garretrieger): cumulative glyf checksum map
+
+ bool in_error () const
+ {
+ return unicode_to_gid.in_error () ||
+ gid_to_unicodes.in_error () ||
+ unicodes.in_error () ||
+ sanitized_table_cache.in_error ();
+ }
+};
+
+
+#endif /* HB_SUBSET_ACCELERATOR_HH */
diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc
index 711b2236d..6e1b6f713 100644
--- a/src/hb-subset-cff-common.cc
+++ b/src/hb-subset-cff-common.cc
@@ -66,8 +66,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
{
/* use hb_set to determine the subset of font dicts */
- hb_set_t *set = hb_set_create ();
- if (unlikely (set == &Null (hb_set_t))) return false;
+ hb_set_t set;
hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
{
@@ -79,7 +78,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
glyph = i;
}
fd = src.get_fd (glyph);
- set->add (fd);
+ set.add (fd);
if (fd != prev_fd)
{
@@ -90,12 +89,11 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
}
}
- subset_fd_count = set->get_population ();
+ subset_fd_count = set.get_population ();
if (subset_fd_count == fdCount)
{
/* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
fdmap.identity (fdCount);
- hb_set_destroy (set);
}
else
{
@@ -103,9 +101,8 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
fdmap.reset ();
hb_codepoint_t fd = CFF_UNDEF_CODE;
- while (set->next (&fd))
+ while (set.next (&fd))
fdmap.add (fd);
- hb_set_destroy (set);
if (unlikely (fdmap.get_population () != subset_fd_count))
return false;
}
diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh
index 7fd96ca86..8bbc01765 100644
--- a/src/hb-subset-cff-common.hh
+++ b/src/hb-subset-cff-common.hh
@@ -38,14 +38,16 @@ namespace CFF {
struct str_encoder_t
{
str_encoder_t (str_buff_t &buff_)
- : buff (buff_), error (false) {}
+ : buff (buff_) {}
- void reset () { buff.resize (0); }
+ void reset () { buff.reset (); }
void encode_byte (unsigned char b)
{
- if (unlikely (buff.push (b) == &Crap (unsigned char)))
- set_error ();
+ if (likely ((signed) buff.length < buff.allocated))
+ buff.arrayZ[buff.length++] = b;
+ else
+ buff.push (b);
}
void encode_int (int v)
@@ -107,29 +109,18 @@ struct str_encoder_t
encode_byte (op);
}
- void copy_str (const byte_str_t &str)
+ void copy_str (const unsigned char *str, unsigned length)
{
- unsigned int offset = buff.length;
- 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);
+ assert ((signed) (buff.length + length) <= buff.allocated);
+ hb_memcpy (buff.arrayZ + buff.length, str, length);
+ buff.length += length;
}
- bool is_error () const { return error; }
+ bool in_error () const { return buff.in_error (); }
protected:
- void set_error () { error = true; }
str_buff_t &buff;
- bool error;
};
struct cff_sub_table_info_t {
@@ -188,9 +179,12 @@ struct cff_font_dict_op_serializer_t : op_serializer_t
}
else
{
- HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+ unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
if (unlikely (!d)) return_trace (false);
- memcpy (d, &opstr.str[0], opstr.str.length);
+ /* Faster than hb_memcpy for small strings. */
+ for (unsigned i = 0; i < opstr.length; i++)
+ d[i] = opstr.ptr[i];
+ //hb_memcpy (d, opstr.ptr, opstr.length);
}
return_trace (true);
}
@@ -240,11 +234,10 @@ struct subr_flattener_t
bool flatten (str_buff_vec_t &flat_charstrings)
{
- if (!flat_charstrings.resize (plan->num_output_glyphs ()))
+ unsigned count = plan->num_output_glyphs ();
+ if (!flat_charstrings.resize (count))
return false;
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
- flat_charstrings[i].init ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (unsigned int i = 0; i < count; i++)
{
hb_codepoint_t glyph;
if (!plan->old_gid_for_new_gid (i, &glyph))
@@ -253,14 +246,14 @@ 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],
+ flat_charstrings.arrayZ[i],
(bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
};
if (unlikely (!interp.interpret (param)))
@@ -275,85 +268,50 @@ struct subr_flattener_t
struct subr_closures_t
{
- subr_closures_t () : valid (false), global_closure (nullptr)
- { local_closures.init (); }
-
- void init (unsigned int fd_count)
+ subr_closures_t (unsigned int fd_count) : global_closure (), local_closures ()
{
- valid = true;
- global_closure = hb_set_create ();
- if (global_closure == hb_set_get_empty ())
- valid = false;
- if (!local_closures.resize (fd_count))
- valid = false;
-
- for (unsigned int i = 0; i < local_closures.length; i++)
- {
- local_closures[i] = hb_set_create ();
- if (local_closures[i] == hb_set_get_empty ())
- valid = false;
- }
- }
-
- void fini ()
- {
- hb_set_destroy (global_closure);
- for (unsigned int i = 0; i < local_closures.length; i++)
- hb_set_destroy (local_closures[i]);
- local_closures.fini ();
+ local_closures.resize (fd_count);
}
void reset ()
{
- hb_set_clear (global_closure);
+ global_closure.clear();
for (unsigned int i = 0; i < local_closures.length; i++)
- hb_set_clear (local_closures[i]);
+ local_closures[i].clear();
}
- bool is_valid () const { return valid; }
- bool valid;
- hb_set_t *global_closure;
- hb_vector_t<hb_set_t *> local_closures;
+ bool in_error () const { return local_closures.in_error (); }
+ hb_set_t global_closure;
+ hb_vector_t<hb_set_t> local_closures;
};
struct parsed_cs_op_t : op_str_t
{
- void init (unsigned int subr_num_ = 0)
- {
- op_str_t::init ();
- subr_num = subr_num_;
- drop_flag = false;
- keep_flag = false;
- skip_flag = false;
- }
-
- void fini () { op_str_t::fini (); }
-
- bool for_drop () const { return drop_flag; }
- void set_drop () { if (!for_keep ()) drop_flag = true; }
-
- bool for_keep () const { return keep_flag; }
- void set_keep () { keep_flag = true; }
+ parsed_cs_op_t (unsigned int subr_num_ = 0) :
+ subr_num (subr_num_) {}
- bool for_skip () const { return skip_flag; }
- void set_skip () { skip_flag = true; }
+ bool is_hinting () const { return hinting_flag; }
+ void set_hinting () { hinting_flag = true; }
- unsigned int subr_num;
+ /* The layout of this struct is designed to fit within the
+ * padding of op_str_t! */
protected:
- bool drop_flag : 1;
- bool keep_flag : 1;
- bool skip_flag : 1;
+ bool hinting_flag = false;
+
+ public:
+ uint16_t subr_num;
};
struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
{
- void init ()
+ parsed_cs_str_t () :
+ parsed (false),
+ hint_dropped (false),
+ has_prefix_ (false),
+ has_calls_ (false)
{
SUPER::init ();
- parsed = false;
- hint_dropped = false;
- has_prefix_ = false;
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref)
@@ -366,13 +324,12 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
{
if (!is_parsed ())
{
- unsigned int parsed_len = get_count ();
- if (likely (parsed_len > 0))
- values[parsed_len-1].set_skip ();
+ has_calls_ = true;
+
+ /* Pop the subroutine number. */
+ values.pop ();
- parsed_cs_op_t val;
- val.init (subr_num);
- SUPER::add_op (op, str_ref, val);
+ SUPER::add_op (op, str_ref, {subr_num});
}
}
@@ -402,11 +359,14 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
op_code_t prefix_op () const { return prefix_op_; }
const number_t &prefix_num () const { return prefix_num_; }
+ bool has_calls () const { return has_calls_; }
+
protected:
- bool parsed;
- bool hint_dropped;
- bool vsindex_dropped;
- bool has_prefix_;
+ bool parsed : 1;
+ bool hint_dropped : 1;
+ bool vsindex_dropped : 1;
+ bool has_prefix_ : 1;
+ bool has_calls_ : 1;
op_code_t prefix_op_;
number_t prefix_num_;
@@ -416,36 +376,79 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
{
- void init (unsigned int len_ = 0)
- {
- SUPER::init ();
- if (unlikely (!resize (len_)))
- return;
- for (unsigned int i = 0; i < length; i++)
- (*this)[i].init ();
- }
- void fini () { SUPER::fini_deep (); }
-
private:
typedef hb_vector_t<parsed_cs_str_t> SUPER;
};
-struct subr_subset_param_t
+struct cff_subset_accelerator_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_)
+ static cff_subset_accelerator_t* create (
+ hb_blob_t* original_blob,
+ const parsed_cs_str_vec_t& parsed_charstrings,
+ const parsed_cs_str_vec_t& parsed_global_subrs,
+ const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
+ cff_subset_accelerator_t* accel =
+ (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
+ new (accel) cff_subset_accelerator_t (original_blob,
+ parsed_charstrings,
+ parsed_global_subrs,
+ parsed_local_subrs);
+ return accel;
+ }
+
+ static void destroy (void* value) {
+ if (!value) return;
+
+ cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
+ accel->~cff_subset_accelerator_t ();
+ hb_free (accel);
+ }
+
+ cff_subset_accelerator_t(
+ hb_blob_t* original_blob_,
+ const parsed_cs_str_vec_t& parsed_charstrings_,
+ const parsed_cs_str_vec_t& parsed_global_subrs_,
+ const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
{
- parsed_charstring = parsed_charstring_;
- current_parsed_str = parsed_charstring;
+ parsed_charstrings = parsed_charstrings_;
parsed_global_subrs = parsed_global_subrs_;
parsed_local_subrs = parsed_local_subrs_;
- global_closure = global_closure_;
- local_closure = local_closure_;
- drop_hints = drop_hints_;
+
+ // the parsed charstrings point to memory in the original CFF table so we must hold a reference
+ // to it to keep the memory valid.
+ original_blob = hb_blob_reference (original_blob_);
}
+ ~cff_subset_accelerator_t() {
+ hb_blob_destroy (original_blob);
+ hb_map_destroy (glyph_to_sid_map.get_relaxed ());
+ }
+
+ parsed_cs_str_vec_t parsed_charstrings;
+ parsed_cs_str_vec_t parsed_global_subrs;
+ hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
+ mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr;
+
+ private:
+ hb_blob_t* original_blob;
+};
+
+struct subr_subset_param_t
+{
+ 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)
{
switch (context.type)
@@ -481,7 +484,11 @@ struct subr_subset_param_t
if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
env.set_error ();
else
+ {
+ if (!parsed_str->is_parsed ())
+ parsed_str->alloc (env.str_ref.total_size () / 2);
current_parsed_str = parsed_str;
+ }
}
parsed_cs_str_t *current_parsed_str;
@@ -496,12 +503,13 @@ struct subr_subset_param_t
struct subr_remap_t : hb_inc_bimap_t
{
- void create (hb_set_t *closure)
+ void create (const hb_set_t *closure)
{
/* create a remapping of subroutine numbers from old to new.
* no optimization based on usage counts. fonttools doesn't appear doing that either.
*/
+ resize (closure->get_population ());
hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
while (hb_set_next (closure, &old_num))
add (old_num);
@@ -526,19 +534,9 @@ struct subr_remap_t : hb_inc_bimap_t
struct subr_remaps_t
{
- subr_remaps_t ()
+ subr_remaps_t (unsigned int fdCount)
{
- global_remap.init ();
- local_remaps.init ();
- }
-
- ~subr_remaps_t () { fini (); }
-
- void init (unsigned int fdCount)
- {
- if (unlikely (!local_remaps.resize (fdCount))) return;
- for (unsigned int i = 0; i < fdCount; i++)
- local_remaps[i].init ();
+ local_remaps.resize (fdCount);
}
bool in_error()
@@ -548,15 +546,9 @@ struct subr_remaps_t
void create (subr_closures_t& closures)
{
- global_remap.create (closures.global_closure);
+ global_remap.create (&closures.global_closure);
for (unsigned int i = 0; i < local_remaps.length; i++)
- local_remaps[i].create (closures.local_closures[i]);
- }
-
- void fini ()
- {
- global_remap.fini ();
- local_remaps.fini_deep ();
+ local_remaps.arrayZ[i].create (&closures.local_closures[i]);
}
subr_remap_t global_remap;
@@ -567,21 +559,9 @@ template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typena
struct subr_subsetter_t
{
subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
- : acc (acc_), plan (plan_)
- {
- parsed_charstrings.init ();
- parsed_global_subrs.init ();
- parsed_local_subrs.init ();
- }
-
- ~subr_subsetter_t ()
- {
- closures.fini ();
- remaps.fini ();
- parsed_charstrings.fini_deep ();
- parsed_global_subrs.fini_deep ();
- parsed_local_subrs.fini_deep ();
- }
+ : acc (acc_), plan (plan_), closures(acc_.fdCount),
+ remaps(acc_.fdCount)
+ {}
/* Subroutine subsetting with --no-desubroutinize runs in phases:
*
@@ -599,56 +579,96 @@ struct subr_subsetter_t
*/
bool subset (void)
{
- closures.init (acc.fdCount);
- remaps.init (acc.fdCount);
+ unsigned fd_count = acc.fdCount;
+ const cff_subset_accelerator_t* cff_accelerator = nullptr;
+ if (plan->accelerator && plan->accelerator->cff_accelerator) {
+ cff_accelerator = plan->accelerator->cff_accelerator;
+ fd_count = cff_accelerator->parsed_local_subrs.length;
+ }
- parsed_charstrings.init (plan->num_output_glyphs ());
- parsed_global_subrs.init (acc.globalSubrs->count);
+ if (cff_accelerator) {
+ // If we are not dropping hinting then charstrings are not modified so we can
+ // just use a reference to the cached copies.
+ cached_charstrings.resize (plan->num_output_glyphs ());
+ parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
+ parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
+ } else {
+ parsed_charstrings.resize (plan->num_output_glyphs ());
+ parsed_global_subrs_storage.resize (acc.globalSubrs->count);
- if (unlikely (remaps.in_error()
- || parsed_charstrings.in_error ()
- || parsed_global_subrs.in_error ())) {
- return false;
- }
+ if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
- if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
+ for (unsigned int i = 0; i < acc.fdCount; i++)
+ {
+ unsigned count = acc.privateDicts[i].localSubrs->count;
+ parsed_local_subrs_storage[i].resize (count);
+ if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
+ }
- for (unsigned int i = 0; i < acc.fdCount; i++)
- {
- parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
- if (unlikely (parsed_local_subrs[i].in_error ())) return false;
+ parsed_global_subrs = &parsed_global_subrs_storage;
+ parsed_local_subrs = &parsed_local_subrs_storage;
}
- if (unlikely (!closures.valid))
+
+ if (unlikely (remaps.in_error()
+ || cached_charstrings.in_error ()
+ || parsed_charstrings.in_error ()
+ || parsed_global_subrs->in_error ()
+ || closures.in_error ())) {
return false;
+ }
/* phase 1 & 2 */
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
{
hb_codepoint_t glyph;
if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
- const byte_str_t str = (*acc.charStrings)[glyph];
+ continue;
+
+ const hb_ubytes_t str = (*acc.charStrings)[glyph];
unsigned int fd = acc.fdSelect->get_fd (glyph);
if (unlikely (fd >= acc.fdCount))
- return false;
+ return false;
- cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
- interp.env.init (str, acc, fd);
+ if (cff_accelerator)
+ {
+ // parsed string already exists in accelerator, copy it and move
+ // on.
+ if (cached_charstrings)
+ cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph];
+ else
+ parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph];
+
+ continue;
+ }
+
+ 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 / 2);
+ subr_subset_param_t param (&parsed_charstrings[i],
+ &parsed_global_subrs_storage,
+ &parsed_local_subrs_storage[fd],
+ &closures.global_closure,
+ &closures.local_closures[fd],
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
if (unlikely (!interp.interpret (param)))
- return false;
+ return false;
/* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
}
- if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ // Since parsed strings were loaded from accelerator, we still need
+ // to compute the subroutine closures which would have normally happened during
+ // parsing.
+ if (cff_accelerator &&
+ !closure_subroutines(*parsed_global_subrs,
+ *parsed_local_subrs))
+ return false;
+
+ if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING && !cff_accelerator) ||
+ plan->inprogress_accelerator)
{
/* mark hint ops and arguments for drop */
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
@@ -659,11 +679,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_storage,
+ &parsed_local_subrs_storage[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))
@@ -675,26 +696,14 @@ struct subr_subsetter_t
}
/* after dropping hints recreate closures of actually used subrs */
- closures.reset ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
- {
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
- 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);
- collect_subr_refs_in_str (parsed_charstrings[i], param);
- }
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING &&
+ !cff_accelerator &&
+ !closure_subroutines(*parsed_global_subrs, *parsed_local_subrs)) return false;
}
remaps.create (closures);
+ populate_subset_accelerator ();
return true;
}
@@ -708,13 +717,13 @@ struct subr_subsetter_t
if (!plan->old_gid_for_new_gid (i, &glyph))
{
/* add an endchar only charstring for a missing glyph if CFF1 */
- if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
+ if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op);
continue;
}
unsigned int fd = acc.fdSelect->get_fd (glyph);
if (unlikely (fd >= acc.fdCount))
return false;
- if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
+ if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i])))
return false;
}
return true;
@@ -726,26 +735,25 @@ struct subr_subsetter_t
if (unlikely (!buffArray.resize (count)))
return false;
- for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
+ for (unsigned int new_num = 0; new_num < count; new_num++)
{
- hb_codepoint_t new_num = remap[old_num];
- if (new_num != CFF_UNDEF_CODE)
- {
- if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
- return false;
- }
+ hb_codepoint_t old_num = remap.backward (new_num);
+ assert (old_num != CFF_UNDEF_CODE);
+
+ if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
+ return false;
}
return true;
}
bool encode_globalsubrs (str_buff_vec_t &buffArray)
{
- return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray);
+ return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
}
bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
{
- return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray);
+ return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
}
protected:
@@ -774,7 +782,7 @@ struct subr_subsetter_t
* then this entire subroutine must be a hint. drop its call. */
if (drop.ends_in_hint)
{
- str.values[pos].set_drop ();
+ str.values[pos].set_hinting ();
/* if this subr call is at the end of the parent subr, propagate the flag
* otherwise reset the flag */
if (!str.at_end (pos))
@@ -782,7 +790,7 @@ struct subr_subsetter_t
}
else if (drop.all_dropped)
{
- str.values[pos].set_drop ();
+ str.values[pos].set_hinting ();
}
return has_hint;
@@ -793,20 +801,22 @@ struct subr_subsetter_t
{
bool seen_hint = false;
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ unsigned count = str.values.length;
+ auto *values = str.values.arrayZ;
+ for (unsigned int pos = 0; pos < count; pos++)
{
bool has_hint = false;
- switch (str.values[pos].op)
+ switch (values[pos].op)
{
case OpCode_callsubr:
has_hint = drop_hints_in_subr (str, pos,
- *param.parsed_local_subrs, str.values[pos].subr_num,
+ *param.parsed_local_subrs, values[pos].subr_num,
param, drop);
break;
case OpCode_callgsubr:
has_hint = drop_hints_in_subr (str, pos,
- *param.parsed_global_subrs, str.values[pos].subr_num,
+ *param.parsed_global_subrs, values[pos].subr_num,
param, drop);
break;
@@ -820,7 +830,7 @@ struct subr_subsetter_t
case OpCode_cntrmask:
if (drop.seen_moveto)
{
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
break;
}
HB_FALLTHROUGH;
@@ -830,13 +840,13 @@ struct subr_subsetter_t
case OpCode_hstem:
case OpCode_vstem:
has_hint = true;
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
if (str.at_end (pos))
drop.ends_in_hint = true;
break;
case OpCode_dotsection:
- str.values[pos].set_drop ();
+ values[pos].set_hinting ();
break;
default:
@@ -847,10 +857,10 @@ struct subr_subsetter_t
{
for (int i = pos - 1; i >= 0; i--)
{
- parsed_cs_op_t &csop = str.values[(unsigned)i];
- if (csop.for_drop ())
+ parsed_cs_op_t &csop = values[(unsigned)i];
+ if (csop.is_hinting ())
break;
- csop.set_drop ();
+ csop.set_hinting ();
if (csop.op == OpCode_vsindexcs)
drop.vsindex_dropped = true;
}
@@ -863,12 +873,12 @@ struct subr_subsetter_t
* only (usually one) hintmask operator, then calls to this subr can be dropped.
*/
drop.all_dropped = true;
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ for (unsigned int pos = 0; pos < count; pos++)
{
- parsed_cs_op_t &csop = str.values[pos];
+ parsed_cs_op_t &csop = values[pos];
if (csop.op == OpCode_return)
break;
- if (!csop.for_drop ())
+ if (!csop.is_hinting ())
{
drop.all_dropped = false;
break;
@@ -878,32 +888,62 @@ struct subr_subsetter_t
return seen_hint;
}
- void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
- unsigned int subr_num, parsed_cs_str_vec_t &subrs,
+ bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs,
+ const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
+ {
+ closures.reset ();
+ for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ {
+ hb_codepoint_t glyph;
+ if (!plan->old_gid_for_new_gid (i, &glyph))
+ continue;
+ unsigned int fd = acc.fdSelect->get_fd (glyph);
+ if (unlikely (fd >= acc.fdCount))
+ return false;
+
+ // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
+ // closure and does not modify any of the charstrings.
+ subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)),
+ const_cast<parsed_cs_str_vec_t*> (&global_subrs),
+ const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
+ &closures.global_closure,
+ &closures.local_closures[fd],
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+ collect_subr_refs_in_str (get_parsed_charstring (i), param);
+ }
+
+ return true;
+ }
+
+ void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs,
hb_set_t *closure,
const subr_subset_param_t &param)
{
+ if (closure->has (subr_num))
+ return;
closure->add (subr_num);
collect_subr_refs_in_str (subrs[subr_num], param);
}
- void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param)
+ void collect_subr_refs_in_str (const parsed_cs_str_t &str,
+ const subr_subset_param_t &param)
{
- for (unsigned int pos = 0; pos < str.values.length; pos++)
+ if (!str.has_calls ())
+ return;
+
+ for (auto &opstr : str.values)
{
- if (!str.values[pos].for_drop ())
+ if (!param.drop_hints || !opstr.is_hinting ())
{
- switch (str.values[pos].op)
+ switch (opstr.op)
{
case OpCode_callsubr:
- collect_subr_refs_in_subr (str, pos,
- str.values[pos].subr_num, *param.parsed_local_subrs,
+ collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
param.local_closure, param);
break;
case OpCode_callgsubr:
- collect_subr_refs_in_subr (str, pos,
- str.values[pos].subr_num, *param.parsed_global_subrs,
+ collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
param.global_closure, param);
break;
@@ -915,41 +955,113 @@ struct subr_subsetter_t
bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
{
- buff.init ();
str_encoder_t encoder (buff);
encoder.reset ();
+ bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
/* 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 ())
+ if (str.has_prefix () && !hinting && str.is_hint_dropped ())
{
encoder.encode_num (str.prefix_num ());
if (str.prefix_op () != OpCode_Invalid)
encoder.encode_op (str.prefix_op ());
}
- for (unsigned int i = 0; i < str.get_count(); i++)
+
+ unsigned size = 0;
+ for (auto &opstr : str.values)
+ {
+ size += opstr.length;
+ if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
+ size += 3;
+ }
+ if (!buff.alloc (buff.length + size))
+ return false;
+
+ for (auto &opstr : str.values)
{
- const parsed_cs_op_t &opstr = str.values[i];
- if (!opstr.for_drop () && !opstr.for_skip ())
+ if (hinting || !opstr.is_hinting ())
{
switch (opstr.op)
{
case OpCode_callsubr:
encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
- encoder.encode_op (OpCode_callsubr);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
case OpCode_callgsubr:
encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
- encoder.encode_op (OpCode_callgsubr);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
default:
- encoder.copy_str (opstr.str);
+ encoder.copy_str (opstr.ptr, opstr.length);
break;
}
}
}
- return !encoder.is_error ();
+ return !encoder.in_error ();
+ }
+
+ void compact_parsed_strings () const
+ {
+ for (auto &cs : parsed_charstrings)
+ compact_string (cs);
+ for (auto &cs : parsed_global_subrs_storage)
+ compact_string (cs);
+ for (auto &vec : parsed_local_subrs_storage)
+ for (auto &cs : vec)
+ compact_string (cs);
+ }
+
+ static void compact_string (parsed_cs_str_t &str)
+ {
+ unsigned count = str.values.length;
+ if (unlikely (!count)) return;
+ auto &opstr = str.values.arrayZ;
+ unsigned j = 0;
+ for (unsigned i = 1; i < count; i++)
+ {
+ /* See if we can combine op j and op i. */
+ bool combine =
+ (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) &&
+ (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) &&
+ (opstr[j].is_hinting () == opstr[i].is_hinting ()) &&
+ (opstr[j].ptr + opstr[j].length == opstr[i].ptr) &&
+ (opstr[j].length + opstr[i].length <= 255);
+
+ if (combine)
+ {
+ opstr[j].length += opstr[i].length;
+ opstr[j].op = OpCode_Invalid;
+ }
+ else
+ {
+ opstr[++j] = opstr[i];
+ }
+ }
+ str.values.shrink (j + 1);
+ }
+
+ void populate_subset_accelerator () const
+ {
+ if (!plan->inprogress_accelerator) return;
+
+ compact_parsed_strings ();
+
+ plan->inprogress_accelerator->cff_accelerator =
+ cff_subset_accelerator_t::create(acc.blob,
+ parsed_charstrings,
+ parsed_global_subrs_storage,
+ parsed_local_subrs_storage);
+ plan->inprogress_accelerator->destroy_cff_accelerator =
+ cff_subset_accelerator_t::destroy;
+
+ }
+
+ const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
+ {
+ if (cached_charstrings) return *(cached_charstrings[i]);
+ return parsed_charstrings[i];
}
protected:
@@ -958,13 +1070,17 @@ struct subr_subsetter_t
subr_closures_t closures;
- parsed_cs_str_vec_t parsed_charstrings;
- parsed_cs_str_vec_t parsed_global_subrs;
- hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
+ hb_vector_t<const parsed_cs_str_t*> cached_charstrings;
+ const parsed_cs_str_vec_t* parsed_global_subrs;
+ const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs;
subr_remaps_t remaps;
private:
+
+ parsed_cs_str_vec_t parsed_charstrings;
+ parsed_cs_str_vec_t parsed_global_subrs_storage;
+ hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs_storage;
typedef typename SUBRS::count_type subr_count_type;
};
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index b4e24122c..538f28f5a 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -167,9 +167,10 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic
* for supplement, the original byte string is copied along with the op code */
op_str_t supp_op;
supp_op.op = op;
- if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3)))
+ if ( unlikely (!(opstr.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.ptr = opstr.ptr + opstr.last_arg_offset;
+ supp_op.length = opstr.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 +271,13 @@ struct range_list_t : hb_vector_t<code_pair_t>
/* replace the first glyph ID in the "glyph" field each range with a nLeft value */
bool complete (unsigned int last_glyph)
{
- bool two_byte = false;
- for (unsigned int i = (*this).length; i > 0; i--)
+ bool two_byte = false;
+ unsigned count = this->length;
+ for (unsigned int i = count; i; i--)
{
- code_pair_t &pair = (*this)[i - 1];
- unsigned int nLeft = last_glyph - pair.glyph - 1;
- if (nLeft >= 0x100)
- two_byte = true;
+ code_pair_t &pair = arrayZ[i - 1];
+ unsigned int nLeft = last_glyph - pair.glyph - 1;
+ two_byte |= nLeft >= 0x100;
last_glyph = pair.glyph;
pair.glyph = nLeft;
}
@@ -362,43 +363,11 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs
struct cff_subset_plan {
cff_subset_plan ()
- : info (),
- orig_fdcount (0),
- subset_fdcount (1),
- subset_fdselect_format (0),
- drop_hints (false),
- desubroutinize(false)
{
- topdict_mod.init ();
- subset_fdselect_ranges.init ();
- fdmap.init ();
- subset_charstrings.init ();
- subset_globalsubrs.init ();
- subset_localsubrs.init ();
- fontdicts_mod.init ();
- subset_enc_code_ranges.init ();
- subset_enc_supp_codes.init ();
- subset_charset_ranges.init ();
- sidmap.init ();
for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
topDictModSIDs[i] = CFF_UNDEF_SID;
}
- ~cff_subset_plan ()
- {
- topdict_mod.fini ();
- subset_fdselect_ranges.fini ();
- fdmap.fini ();
- subset_charstrings.fini_deep ();
- subset_globalsubrs.fini_deep ();
- subset_localsubrs.fini_deep ();
- fontdicts_mod.fini ();
- subset_enc_code_ranges.fini ();
- subset_enc_supp_codes.fini ();
- subset_charset_ranges.fini ();
- sidmap.fini ();
- }
-
void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
{
const Encoding *encoding = acc.encoding;
@@ -474,6 +443,18 @@ struct cff_subset_plan {
return;
}
+ hb_map_t *glyph_to_sid_map = (plan->accelerator && plan->accelerator->cff_accelerator) ?
+ plan->accelerator->cff_accelerator->glyph_to_sid_map :
+ nullptr;
+ bool created_map = false;
+ if (!glyph_to_sid_map &&
+ ((plan->accelerator && plan->accelerator->cff_accelerator) ||
+ plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.))
+ {
+ created_map = true;
+ glyph_to_sid_map = acc.create_glyph_to_sid_map ();
+ }
+
unsigned int glyph;
for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
{
@@ -483,7 +464,7 @@ struct cff_subset_plan {
/* Retain the SID for the old missing glyph ID */
old_glyph = glyph;
}
- sid = acc.glyph_to_sid (old_glyph);
+ sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph);
if (!acc.is_CID ())
sid = sidmap.add (sid);
@@ -496,6 +477,13 @@ struct cff_subset_plan {
last_sid = sid;
}
+ if (created_map)
+ {
+ if (!(plan->accelerator && plan->accelerator->cff_accelerator) ||
+ !plan->accelerator->cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
+ hb_map_destroy (glyph_to_sid_map);
+ }
+
bool two_byte = subset_charset_ranges.complete (glyph);
size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
@@ -672,9 +660,9 @@ struct cff_subset_plan {
cff1_sub_table_info_t info;
unsigned int num_glyphs;
- unsigned int orig_fdcount;
- unsigned int subset_fdcount;
- unsigned int subset_fdselect_format;
+ unsigned int orig_fdcount = 0;
+ unsigned int subset_fdcount = 1;
+ unsigned int subset_fdselect_format = 0;
hb_vector_t<code_pair_t> subset_fdselect_ranges;
/* font dict index remap table from fullset FDArray to subset FDArray.
@@ -686,7 +674,7 @@ struct cff_subset_plan {
hb_vector_t<str_buff_vec_t> subset_localsubrs;
hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod;
- bool drop_hints;
+ bool drop_hints = false;
bool gid_renum;
bool subset_encoding;
@@ -702,7 +690,7 @@ struct cff_subset_plan {
remap_sid_t sidmap;
unsigned int topDictModSIDs[name_dict_values_t::ValCount];
- bool desubroutinize;
+ bool desubroutinize = false;
};
static bool _serialize_cff1 (hb_serialize_context_t *c,
@@ -754,11 +742,17 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* CharStrings */
{
+ c->push<CFF1CharStrings> ();
+
+ unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> ();
if (unlikely (!cs)) return false;
- c->push ();
+
if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack ();
+ plan.info.char_strings_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -841,7 +835,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
if (unlikely (!dest)) return false;
if (likely (dest->serialize (c, plan.subset_globalsubrs)))
- c->pop_pack ();
+ c->pop_pack (false);
else
{
c->pop_discard ();
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 896ae6401..60946b028 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -67,9 +67,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
}
};
-struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t>
+struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t>
{
- static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
{
switch (op)
{
@@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
}
}
- static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flush_args (cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
{
for (unsigned int i = 0; i < env.argStack.get_count ();)
{
@@ -122,7 +122,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
SUPER::flush_args (env, param);
}
- static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
{
/* flatten the default values */
str_encoder_t encoder (param.flatStr);
@@ -149,7 +149,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
encoder.encode_op (OpCode_blendcs);
}
- static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
+ static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
{
switch (op)
{
@@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
}
private:
- typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER;
- typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET;
+ typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER;
+ typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_t>, flatten_param_t> CSOPSET;
};
-struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t>
+struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t>
{
- static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param)
+ static void process_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param)
{
switch (op) {
@@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
protected:
static void process_call_subr (op_code_t op, cs_type_t type,
- cff2_cs_interp_env_t &env, subr_subset_param_t& param,
+ cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param,
cff2_biased_subrs_t& subrs, hb_set_t *closure)
{
byte_str_ref_t str_ref = env.str_ref;
@@ -212,15 +212,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
}
private:
- typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
+ typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> SUPER;
};
-struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
+struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_subr_subset_t>
{
cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
: subr_subsetter_t (acc_, plan_) {}
- static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
+ static void complete_parsed_str (cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
{
/* vsindex is inserted at the beginning of the charstring as necessary */
if (env.seen_vsindex ())
@@ -233,29 +233,6 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs
};
struct cff2_subset_plan {
- cff2_subset_plan ()
- : orig_fdcount (0),
- subset_fdcount(1),
- subset_fdselect_size (0),
- subset_fdselect_format (0),
- drop_hints (false),
- desubroutinize (false)
- {
- subset_fdselect_ranges.init ();
- fdmap.init ();
- subset_charstrings.init ();
- subset_globalsubrs.init ();
- subset_localsubrs.init ();
- }
-
- ~cff2_subset_plan ()
- {
- subset_fdselect_ranges.fini ();
- fdmap.fini ();
- subset_charstrings.fini_deep ();
- subset_globalsubrs.fini_deep ();
- subset_localsubrs.fini_deep ();
- }
bool create (const OT::cff2::accelerator_subset_t &acc,
hb_subset_plan_t *plan)
@@ -268,7 +245,7 @@ struct cff2_subset_plan {
if (desubroutinize)
{
/* Flatten global & local subrs */
- subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
+ subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t>
flattener(acc, plan);
if (!flattener.flatten (subset_charstrings))
return false;
@@ -320,10 +297,10 @@ struct cff2_subset_plan {
cff2_sub_table_info_t info;
- unsigned int orig_fdcount;
- unsigned int subset_fdcount;
- unsigned int subset_fdselect_size;
- unsigned int subset_fdselect_format;
+ unsigned int orig_fdcount = 0;
+ unsigned int subset_fdcount = 1;
+ unsigned int subset_fdselect_size = 0;
+ unsigned int subset_fdselect_format = 0;
hb_vector_t<code_pair_t> subset_fdselect_ranges;
hb_inc_bimap_t fdmap;
@@ -332,8 +309,8 @@ struct cff2_subset_plan {
str_buff_vec_t subset_globalsubrs;
hb_vector_t<str_buff_vec_t> subset_localsubrs;
- bool drop_hints;
- bool desubroutinize;
+ bool drop_hints = false;
+ bool desubroutinize = false;
};
static bool _serialize_cff2 (hb_serialize_context_t *c,
@@ -357,7 +334,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (unlikely (!dest)) return false;
c->push ();
if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
- subrs_link = c->pop_pack ();
+ subrs_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -384,11 +361,17 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
/* CharStrings */
{
+ c->push ();
+
+ unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
CFF2CharStrings *cs = c->start_embed<CFF2CharStrings> ();
if (unlikely (!cs)) return false;
- c->push ();
+
if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack ();
+ plan.info.char_strings_link = c->pop_pack (false);
else
{
c->pop_discard ();
@@ -400,9 +383,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (acc.fdSelect != &Null (CFF2FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, plan.orig_fdcount,
- plan.subset_fdselect_format, plan.subset_fdselect_size,
- plan.subset_fdselect_ranges)))
+ if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,
+ plan.orig_fdcount,
+ plan.subset_fdselect_format, plan.subset_fdselect_size,
+ plan.subset_fdselect_ranges)))
plan.info.fd_select.link = c->pop_pack ();
else
{
@@ -424,7 +408,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
hb_iter (private_dict_infos))
;
if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
- plan.info.fd_array_link = c->pop_pack ();
+ plan.info.fd_array_link = c->pop_pack (false);
}
/* variation store */
@@ -433,7 +417,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
c->push ();
CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
- plan.info.var_store_link = c->pop_pack ();
+ plan.info.var_store_link = c->pop_pack (false);
}
OT::cff2 *cff2 = c->allocate_min<OT::cff2> ();
@@ -473,12 +457,8 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
bool
hb_subset_cff2 (hb_subset_context_t *c)
{
- OT::cff2::accelerator_subset_t acc;
- acc.init (c->plan->source);
- bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c);
- acc.fini ();
-
- return result;
+ OT::cff2::accelerator_subset_t acc (c->plan->source);
+ return acc.is_valid () && _hb_subset_cff2 (acc, c);
}
#endif
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index 488528099..42434ae0e 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -26,13 +26,13 @@
#include "hb-subset.hh"
#include "hb-set.hh"
-
+#include "hb-utf.hh"
/**
* hb_subset_input_create_or_fail:
*
* Creates a new subset input object.
*
- * Return value: (transfer full): New subset input, or %NULL if failed. Destroy
+ * Return value: (transfer full): New subset input, or `NULL` if failed. Destroy
* with hb_subset_input_destroy().
*
* Since: 1.8.0
@@ -48,7 +48,16 @@ hb_subset_input_create_or_fail (void)
for (auto& set : input->sets_iter ())
set = hb_set_create ();
- if (input->in_error ())
+ input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
+#ifdef HB_EXPERIMENTAL_API
+ input->name_table_overrides = hb_hashmap_create<hb_ot_name_record_ids_t, hb_bytes_t> ();
+#endif
+
+ if (!input->axes_location ||
+#ifdef HB_EXPERIMENTAL_API
+ !input->name_table_overrides ||
+#endif
+ input->in_error ())
{
hb_subset_input_destroy (input);
return nullptr;
@@ -87,7 +96,6 @@ hb_subset_input_create_or_fail (void)
hb_tag_t default_no_subset_tables[] = {
HB_TAG ('a', 'v', 'a', 'r'),
- HB_TAG ('f', 'v', 'a', 'r'),
HB_TAG ('g', 'a', 's', 'p'),
HB_TAG ('c', 'v', 't', ' '),
HB_TAG ('f', 'p', 'g', 'm'),
@@ -96,7 +104,6 @@ hb_subset_input_create_or_fail (void)
HB_TAG ('D', 'S', 'I', 'G'),
HB_TAG ('M', 'V', 'A', 'R'),
HB_TAG ('c', 'v', 'a', 'r'),
- HB_TAG ('S', 'T', 'A', 'T'),
};
input->sets.no_subset_tables->add_array (default_no_subset_tables,
ARRAY_LENGTH (default_no_subset_tables));
@@ -140,7 +147,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'),
@@ -190,6 +210,8 @@ hb_subset_input_create_or_fail (void)
input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
+ input->sets.layout_scripts->invert (); // Default to all scripts.
+
if (input->in_error ())
{
hb_subset_input_destroy (input);
@@ -231,6 +253,17 @@ hb_subset_input_destroy (hb_subset_input_t *input)
for (hb_set_t* set : input->sets_iter ())
hb_set_destroy (set);
+ hb_hashmap_destroy (input->axes_location);
+
+#ifdef HB_EXPERIMENTAL_API
+ if (input->name_table_overrides)
+ {
+ for (auto _ : *input->name_table_overrides)
+ _.second.fini ();
+ }
+ hb_hashmap_destroy (input->name_table_overrides);
+#endif
+
hb_free (input);
}
@@ -329,7 +362,7 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
*
* Attaches a user-data key/data pair to the given subset input object.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 2.9.0
**/
@@ -361,3 +394,207 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
{
return hb_object_get_user_data (input, key);
}
+
+#ifndef HB_NO_VAR
+/**
+ * hb_subset_input_pin_axis_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ *
+ * Pin an axis to its default location in the given subset input object.
+ *
+ * Currently only works for fonts with 'glyf' tables. CFF and CFF2 is not
+ * yet supported. Additionally all axes in a font must be pinned.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 6.0.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag)
+{
+ hb_ot_var_axis_info_t axis_info;
+ if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+ return false;
+
+ return input->axes_location->set (axis_tag, axis_info.default_value);
+}
+
+/**
+ * hb_subset_input_pin_axis_location: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ * @axis_value: Location on the axis to be pinned at
+ *
+ * Pin an axis to a fixed location in the given subset input object.
+ *
+ * Currently only works for fonts with 'glyf' tables. CFF and CFF2 is not
+ * yet supported. Additionally all axes in a font must be pinned.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 6.0.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_value)
+{
+ hb_ot_var_axis_info_t axis_info;
+ if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+ return false;
+
+ float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
+ return input->axes_location->set (axis_tag, val);
+}
+#endif
+
+/**
+ * hb_subset_preprocess:
+ * @source: a #hb_face_t object.
+ *
+ * Preprocesses the face and attaches data that will be needed by the
+ * subsetter. Future subsetting operations can then use the precomputed data
+ * to speed up the subsetting operation.
+ *
+ * See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md)
+ * for more information.
+ *
+ * Note: the preprocessed face may contain sub-blobs that reference the memory
+ * backing the source #hb_face_t. Therefore in the case that this memory is not
+ * owned by the source face you will need to ensure that memory lives
+ * as long as the returned #hb_face_t.
+ *
+ * Returns: a new #hb_face_t.
+ *
+ * Since: 6.0.0
+ **/
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source)
+{
+ hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+ if (!input)
+ return source;
+
+ hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+ hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+
+ hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_GLYPH_INDEX));
+ hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_GLYPH_INDEX));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_ID));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_ID));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_LANG_ID));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_LANG_ID));
+
+ hb_subset_input_set_flags(input,
+ HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+ HB_SUBSET_FLAGS_GLYPH_NAMES |
+ HB_SUBSET_FLAGS_RETAIN_GIDS |
+ HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES);
+ input->attach_accelerator_data = true;
+
+ // Always use long loca in the preprocessed version. This allows
+ // us to store the glyph bytes unpadded which allows the future subset
+ // operation to run faster by skipping the trim padding step.
+ input->force_long_loca = true;
+
+ hb_face_t* new_source = hb_subset_or_fail (source, input);
+ hb_subset_input_destroy (input);
+
+ if (!new_source) {
+ DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure.");
+ return source;
+ }
+
+ return new_source;
+}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_override_name_table:
+ * @input: a #hb_subset_input_t object.
+ * @name_id: name_id of a nameRecord
+ * @platform_id: platform ID of a nameRecord
+ * @encoding_id: encoding ID of a nameRecord
+ * @language_id: language ID of a nameRecord
+ * @name_str: pointer to name string new value or null to indicate should remove
+ * @str_len: the size of @name_str, or -1 if it is `NULL`-terminated
+ *
+ * Override the name string of the NameRecord identified by name_id,
+ * platform_id, encoding_id and language_id. If a record with that name_id
+ * doesn't exist, create it and insert to the name table.
+ *
+ * Note: for mac platform, we only support name_str with all ascii characters,
+ * name_str with non-ascii characters will be ignored.
+ *
+ * Since: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t *input,
+ hb_ot_name_id_t name_id,
+ unsigned platform_id,
+ unsigned encoding_id,
+ unsigned language_id,
+ const char *name_str,
+ int str_len /* -1 means nul-terminated */)
+{
+ if (!name_str)
+ {
+ str_len = 0;
+ }
+ else if (str_len == -1)
+ {
+ str_len = strlen (name_str);
+ }
+
+ hb_bytes_t name_bytes (nullptr, 0);
+ if (str_len)
+ {
+ if (platform_id == 1)
+ {
+ const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str);
+ const uint8_t *src_end = src + str_len;
+
+ hb_codepoint_t unicode;
+ const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+ while (src < src_end)
+ {
+ src = hb_utf8_t::next (src, src_end, &unicode, replacement);
+ if (unicode >= 0x0080u)
+ {
+ printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");
+ return false;
+ }
+ }
+ }
+ char *override_name = (char *) hb_malloc (str_len);
+ if (unlikely (!override_name)) return false;
+
+ hb_memcpy (override_name, name_str, str_len);
+ name_bytes = hb_bytes_t (override_name, str_len);
+ }
+ input->name_table_overrides->set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
+ return true;
+}
+
+#endif
diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh
index 07c0e2267..ecd47b7ab 100644
--- a/src/hb-subset-input.hh
+++ b/src/hb-subset-input.hh
@@ -36,6 +36,48 @@
#include "hb-font.hh"
+struct hb_ot_name_record_ids_t
+{
+ hb_ot_name_record_ids_t () = default;
+ hb_ot_name_record_ids_t (unsigned platform_id_,
+ unsigned encoding_id_,
+ unsigned language_id_,
+ unsigned name_id_)
+ :platform_id (platform_id_),
+ encoding_id (encoding_id_),
+ language_id (language_id_),
+ name_id (name_id_) {}
+
+ bool operator != (const hb_ot_name_record_ids_t o) const
+ { return !(*this == o); }
+
+ inline bool operator == (const hb_ot_name_record_ids_t& o) const
+ {
+ return platform_id == o.platform_id &&
+ encoding_id == o.encoding_id &&
+ language_id == o.language_id &&
+ name_id == o.name_id;
+ }
+
+ inline uint32_t hash () const
+ {
+ uint32_t current = 0;
+ current = current * 31 + hb_hash (platform_id);
+ current = current * 31 + hb_hash (encoding_id);
+ current = current * 31 + hb_hash (language_id);
+ current = current * 31 + hb_hash (name_id);
+ return current;
+ }
+
+ unsigned platform_id;
+ unsigned encoding_id;
+ unsigned language_id;
+ unsigned name_id;
+};
+
+typedef struct hb_ot_name_record_ids_t hb_ot_name_record_ids_t;
+
+
HB_MARK_AS_FLAG_T (hb_subset_flags_t);
struct hb_subset_input_t
@@ -50,6 +92,7 @@ struct hb_subset_input_t
hb_set_t *name_ids;
hb_set_t *name_languages;
hb_set_t *layout_features;
+ hb_set_t *layout_scripts;
};
union {
@@ -58,6 +101,15 @@ struct hb_subset_input_t
};
unsigned flags;
+ bool attach_accelerator_data = false;
+
+ // If set loca format will always be the long version.
+ bool force_long_loca = false;
+
+ hb_hashmap_t<hb_tag_t, float> *axes_location;
+#ifdef HB_EXPERIMENTAL_API
+ hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides;
+#endif
inline unsigned num_sets () const
{
@@ -76,7 +128,12 @@ struct hb_subset_input_t
if (unlikely (set_ptrs[i]->in_error ()))
return true;
}
- return false;
+
+ return axes_location->in_error ()
+#ifdef HB_EXPERIMENTAL_API
+ || name_table_overrides->in_error ()
+#endif
+ ;
}
};
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 1e195ff66..71bc908ff 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -25,7 +25,9 @@
*/
#include "hb-subset-plan.hh"
+#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
+#include "hb-multimap.hh"
#include "hb-set.hh"
#include "hb-ot-cmap-table.hh"
@@ -37,13 +39,16 @@
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-colrv1-closure.hh"
#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-var-avar-table.hh"
#include "hb-ot-stat-table.hh"
#include "hb-ot-math-table.hh"
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
-typedef hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> 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
+static inline bool
_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
@@ -53,7 +58,9 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
{
gids_to_retain->add (base_gid);
gids_to_retain->add (accent_gid);
+ return true;
}
+ return false;
}
#endif
@@ -78,102 +85,223 @@ static void
_remap_indexes (const hb_set_t *indexes,
hb_map_t *mapping /* OUT */)
{
- unsigned count = indexes->get_population ();
-
- for (auto _ : + hb_zip (indexes->iter (), hb_range (count)))
- mapping->set (_.first, _.second);
+ for (auto _ : + hb_enumerate (indexes->iter ()))
+ mapping->set (_.second, _.first);
}
#ifndef HB_NO_SUBSET_LAYOUT
-typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */);
+/*
+ * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
+ * Returns true if anything was removed (not including duplicates).
+ */
+static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
+ const hb_set_t* filter)
+{
+ hb_vector_t<hb_tag_t> out;
+ out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator.
+
+ bool removed = false;
+ hb_set_t visited;
+
+ for (hb_tag_t tag : *tags)
+ {
+ if (!tag) continue;
+ if (visited.has (tag)) continue;
+
+ if (!filter->has (tag))
+ {
+ removed = true;
+ continue;
+ }
+
+ visited.add (tag);
+ out.push (tag);
+ }
+
+ // The collect function needs a null element to signal end of the array.
+ out.push (HB_TAG_NONE);
+
+ hb_swap (out, *tags);
+ return removed;
+}
template <typename T>
-static void _collect_layout_indices (hb_face_t *face,
+static void _collect_layout_indices (hb_subset_plan_t *plan,
const T& table,
- const hb_set_t *layout_features_to_retain,
- layout_collect_func_t layout_collect_func,
- hb_set_t *indices /* OUT */)
+ hb_set_t *lookup_indices, /* OUT */
+ hb_set_t *feature_indices, /* OUT */
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
{
+ unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features;
- if (!features.alloc (table.get_feature_count () + 1))
+ if (!plan->check_success (features.resize (num_features))) return;
+ table.get_feature_tags (0, &num_features, features.arrayZ);
+ bool retain_all_features = !_filter_tag_list (&features, plan->layout_features);
+
+ unsigned num_scripts = table.get_script_count ();
+ hb_vector_t<hb_tag_t> scripts;
+ if (!plan->check_success (scripts.resize (num_scripts))) return;
+ table.get_script_tags (0, &num_scripts, scripts.arrayZ);
+ bool retain_all_scripts = !_filter_tag_list (&scripts, plan->layout_scripts);
+
+ if (!plan->check_success (!features.in_error ()) || !features
+ || !plan->check_success (!scripts.in_error ()) || !scripts)
return;
- for (unsigned i = 0; i < table.get_feature_count (); i++)
+ hb_ot_layout_collect_features (plan->source,
+ T::tableTag,
+ retain_all_scripts ? nullptr : scripts.arrayZ,
+ nullptr,
+ retain_all_features ? nullptr : features.arrayZ,
+ feature_indices);
+
+#ifndef HB_NO_VAR
+ // collect feature substitutes with variations
+ if (!plan->user_axes_location->is_empty ())
{
- hb_tag_t tag = table.get_feature_tag (i);
- if (tag && layout_features_to_retain->has (tag))
- features.push (tag);
+ hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
+ OT::hb_collect_feature_substitutes_with_var_context_t c =
+ {
+ plan->axes_old_index_tag_map,
+ plan->axes_location,
+ feature_record_cond_idx_map,
+ feature_substitutes_map,
+ feature_indices,
+ true,
+ 0,
+ &conditionset_map
+ };
+ table.collect_feature_substitutes_with_variations (&c);
}
+#endif
- if (!features)
- return;
+ for (unsigned feature_index : *feature_indices)
+ {
+ const OT::Feature* f = &(table.get_feature (feature_index));
+ const OT::Feature **p = nullptr;
+ if (feature_substitutes_map->has (feature_index, &p))
+ f = *p;
- // The collect function needs a null element to signal end of the array.
- features.push (0);
+ f->add_lookup_indexes_to (lookup_indices);
+ }
- if (features.get_size () == table.get_feature_count () + 1)
+ table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
+}
+
+
+static inline void
+_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
+ const hb_map_t *lookup_indices,
+ const hb_set_t *feature_indices,
+ const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
+ hb_map_t *duplicate_feature_map /* OUT */)
+{
+ if (feature_indices->is_empty ()) return;
+ 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 ())
{
- // Looking for all features, trigger the faster collection method.
- layout_collect_func (face,
- T::tableTag,
- nullptr,
- nullptr,
- nullptr,
- indices);
- return;
- }
+ hb_tag_t t = g.get_feature_tag (i);
+ if (t == HB_MAP_VALUE_INVALID) continue;
+ if (!unique_features.has (t))
+ {
+ if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
+ return;
+ if (unique_features.has (t))
+ unique_features.get (t)->add (i);
+ duplicate_feature_map->set (i, i);
+ continue;
+ }
- layout_collect_func (face,
- T::tableTag,
- nullptr,
- nullptr,
- features.arrayZ,
- indices);
+ bool found = false;
+
+ hb_set_t* same_tag_features = unique_features.get (t);
+ for (unsigned other_f_index : same_tag_features->iter ())
+ {
+ const OT::Feature* f = &(g.get_feature (i));
+ const OT::Feature **p = nullptr;
+ if (feature_substitutes_map->has (i, &p))
+ f = *p;
+
+ const OT::Feature* other_f = &(g.get_feature (other_f_index));
+ if (feature_substitutes_map->has (other_f_index, &p))
+ f = *p;
+
+ auto f_iter =
+ + hb_iter (f->lookupIndex)
+ | hb_filter (lookup_indices)
+ ;
+
+ auto other_f_iter =
+ + hb_iter (other_f->lookupIndex)
+ | hb_filter (lookup_indices)
+ ;
+
+ bool is_equal = true;
+ for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
+ {
+ unsigned a = *f_iter;
+ unsigned b = *other_f_iter;
+ if (a != b) { is_equal = false; break; }
+ }
+
+ if (is_equal == false || f_iter || other_f_iter) continue;
+
+ found = true;
+ duplicate_feature_map->set (i, other_f_index);
+ break;
+ }
+
+ if (found == false)
+ {
+ same_tag_features->add (i);
+ duplicate_feature_map->set (i, i);
+ }
+ }
}
template <typename T>
static inline void
-_closure_glyphs_lookups_features (hb_face_t *face,
+_closure_glyphs_lookups_features (hb_subset_plan_t *plan,
hb_set_t *gids_to_retain,
- const hb_set_t *layout_features_to_retain,
hb_map_t *lookups,
hb_map_t *features,
- script_langsys_map *langsys_map)
+ script_langsys_map *langsys_map,
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
{
- hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
+ hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag;
- hb_set_t lookup_indices;
- _collect_layout_indices<T> (face,
+ hb_set_t lookup_indices, feature_indices;
+ _collect_layout_indices<T> (plan,
*table,
- layout_features_to_retain,
- hb_ot_layout_collect_lookups,
- &lookup_indices);
+ &lookup_indices,
+ &feature_indices,
+ feature_record_cond_idx_map,
+ feature_substitutes_map);
if (table_tag == HB_OT_TAG_GSUB)
- hb_ot_layout_lookups_substitute_closure (face,
- &lookup_indices,
+ hb_ot_layout_lookups_substitute_closure (plan->source,
+ &lookup_indices,
gids_to_retain);
- table->closure_lookups (face,
+ table->closure_lookups (plan->source,
gids_to_retain,
- &lookup_indices);
+ &lookup_indices);
_remap_indexes (&lookup_indices, lookups);
- // Collect and prune features
- hb_set_t feature_indices;
- _collect_layout_indices<T> (face,
- *table,
- layout_features_to_retain,
- hb_ot_layout_collect_features,
- &feature_indices);
-
- table->prune_features (lookups, &feature_indices);
+ // prune features
+ table->prune_features (lookups,
+ plan->user_axes_location->is_empty () ? nullptr : feature_record_cond_idx_map,
+ feature_substitutes_map,
+ &feature_indices);
hb_map_t duplicate_feature_map;
- table->find_duplicate_features (lookups, &feature_indices, &duplicate_feature_map);
+ _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
feature_indices.clear ();
- table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
+ table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
_remap_indexes (&feature_indices, features);
table.destroy ();
@@ -183,14 +311,51 @@ _closure_glyphs_lookups_features (hb_face_t *face,
#ifndef HB_NO_VAR
static inline void
- _collect_layout_variation_indices (hb_face_t *face,
- const hb_set_t *glyphset,
- const hb_map_t *gpos_lookups,
- hb_set_t *layout_variation_indices,
- hb_map_t *layout_variation_idx_map)
+_generate_varstore_inner_maps (const hb_set_t& varidx_set,
+ unsigned subtable_count,
+ hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
+{
+ if (varidx_set.is_empty () || subtable_count == 0) return;
+
+ inner_maps.resize (subtable_count);
+ for (unsigned idx : varidx_set)
+ {
+ uint16_t major = idx >> 16;
+ uint16_t minor = idx & 0xFFFF;
+
+ if (major >= subtable_count)
+ continue;
+ inner_maps[major].add (minor);
+ }
+}
+
+static inline hb_font_t*
+_get_hb_font_with_variations (const hb_subset_plan_t *plan)
{
- 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_font_t *font = hb_font_create (plan->source);
+
+ hb_vector_t<hb_variation_t> vars;
+ vars.alloc (plan->user_axes_location->get_population ());
+
+ for (auto _ : *plan->user_axes_location)
+ {
+ hb_variation_t var;
+ var.tag = _.first;
+ var.value = _.second;
+ vars.push (var);
+ }
+
+#ifndef HB_NO_VAR
+ hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+#endif
+ return font;
+}
+
+static inline void
+_collect_layout_variation_indices (hb_subset_plan_t* plan)
+{
+ hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
+ hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
if (!gdef->has_data ())
{
@@ -198,13 +363,40 @@ static inline void
gpos.destroy ();
return;
}
- OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups);
+
+ const OT::VariationStore *var_store = nullptr;
+ hb_set_t varidx_set;
+ hb_font_t *font = nullptr;
+ float *store_cache = nullptr;
+ bool collect_delta = plan->pinned_at_default ? false : true;
+ if (collect_delta)
+ {
+ font = _get_hb_font_with_variations (plan);
+ if (gdef->has_var_store ())
+ {
+ var_store = &(gdef->get_var_store ());
+ store_cache = var_store->create_cache ();
+ }
+ }
+
+ OT::hb_collect_variation_indices_context_t c (&varidx_set,
+ plan->layout_variation_idx_delta_map,
+ font, var_store,
+ plan->_glyphset_gsub,
+ plan->gpos_lookups,
+ store_cache);
gdef->collect_variation_indices (&c);
- if (hb_ot_layout_has_positioning (face))
+ if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c);
- gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
+ hb_font_destroy (font);
+ var_store->destroy_cache (store_cache);
+
+ gdef->remap_layout_variation_indices (&varidx_set, plan->layout_variation_idx_delta_map);
+
+ unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
+ _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
gdef.destroy ();
gpos.destroy ();
@@ -216,10 +408,8 @@ _cmap_closure (hb_face_t *face,
const hb_set_t *unicodes,
hb_set_t *glyphset)
{
- OT::cmap::accelerator_t cmap;
- cmap.init (face);
+ OT::cmap::accelerator_t cmap (face);
cmap.table->closure_glyphs (unicodes, glyphset);
- cmap.fini ();
}
static void _colr_closure (hb_face_t *face,
@@ -227,39 +417,30 @@ static void _colr_closure (hb_face_t *face,
hb_map_t *palettes_map,
hb_set_t *glyphs_colred)
{
- OT::COLR::accelerator_t colr;
- colr.init (face);
+ OT::COLR::accelerator_t colr (face);
if (!colr.is_valid ()) return;
- unsigned iteration_count = 0;
hb_set_t palette_indices, layer_indices;
- unsigned glyphs_num;
- {
- glyphs_num = glyphs_colred->get_population ();
-
- // Collect all glyphs referenced by COLRv0
- hb_set_t glyphset_colrv0;
- for (hb_codepoint_t gid : glyphs_colred->iter ())
- colr.closure_glyphs (gid, &glyphset_colrv0);
-
- glyphs_colred->union_ (glyphset_colrv0);
-
- //closure for COLRv1
- colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
- } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
- glyphs_num != glyphs_colred->get_population ());
+ // Collect all glyphs referenced by COLRv0
+ hb_set_t glyphset_colrv0;
+ for (hb_codepoint_t gid : *glyphs_colred)
+ colr.closure_glyphs (gid, &glyphset_colrv0);
+
+ glyphs_colred->union_ (glyphset_colrv0);
+
+ //closure for COLRv1
+ colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
_remap_indexes (&layer_indices, layers_map);
_remap_palette_indexes (&palette_indices, palettes_map);
- colr.fini ();
}
static inline void
-_math_closure (hb_face_t *face,
- hb_set_t *glyphset)
+_math_closure (hb_subset_plan_t *plan,
+ hb_set_t *glyphset)
{
- hb_blob_ptr_t<OT::MATH> math = hb_sanitize_context_t ().reference_table<OT::MATH> (face);
+ hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> ();
if (math->has_data ())
math->closure_glyphs (glyphset);
math.destroy ();
@@ -270,12 +451,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
@@ -283,46 +459,113 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
const hb_set_t *glyphs,
hb_subset_plan_t *plan)
{
- OT::cmap::accelerator_t cmap;
- cmap.init (plan->source);
-
- constexpr static const int size_threshold = 4096;
-
+ OT::cmap::accelerator_t cmap (plan->source);
+ unsigned size_threshold = plan->source->get_num_glyphs ();
if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
{
- /* This is the fast path if it's anticipated that size of unicodes
- * is << than the number of codepoints in the font. */
- for (hb_codepoint_t cp : *unicodes)
- {
- hb_codepoint_t gid;
- if (!cmap.get_nominal_glyph (cp, &gid))
+
+ const hb_map_t* unicode_to_gid = nullptr;
+ if (plan->accelerator)
+ unicode_to_gid = &plan->accelerator->unicode_to_gid;
+
+ // 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 ());
+ if (!unicode_to_gid) {
+ for (hb_codepoint_t cp : *unicodes)
{
- DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
- continue;
+ hb_codepoint_t gid;
+ if (!cmap.get_nominal_glyph (cp, &gid))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+ continue;
+ }
+
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ } else {
+ // Use in memory unicode to gid map it's faster then looking up from
+ // the map. This code is mostly duplicated from above to avoid doing
+ // conditionals on the presence of the unicode_to_gid map each
+ // iteration.
+ for (hb_codepoint_t cp : *unicodes)
+ {
+ hb_codepoint_t gid = unicode_to_gid->get (cp);
+ if (gid == HB_MAP_VALUE_INVALID)
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+ continue;
+ }
+
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
-
- plan->codepoint_to_glyph->set (cp, gid);
}
}
else
{
- hb_map_t unicode_glyphid_map;
- cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
+ // 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_storage;
+ hb_set_t cmap_unicodes_storage;
+ const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
+ const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
+
+ if (!plan->accelerator) {
+ cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
+ plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
+ + glyphs->get_population (),
+ cmap_unicodes->get_population ()));
+ } else {
+ unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
+ cmap_unicodes = &plan->accelerator->unicodes;
+ }
- for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
- + unicode_glyphid_map.iter ())
+ if (plan->accelerator &&
+ unicodes->get_population () < cmap_unicodes->get_population () &&
+ glyphs->get_population () < cmap_unicodes->get_population ())
{
- if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second))
- continue;
+ auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
+ for (hb_codepoint_t gid : *glyphs)
+ {
+ auto unicodes = gid_to_unicodes.get (gid);
+
+ for (hb_codepoint_t cp : unicodes)
+ {
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ }
+ for (hb_codepoint_t cp : *unicodes)
+ {
+ /* Don't double-add entry. */
+ if (plan->codepoint_to_glyph->has (cp))
+ continue;
- plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ plan->unicode_to_new_gid_list.qsort ();
+ }
+ else
+ {
+ for (hb_codepoint_t cp : *cmap_unicodes)
+ {
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+ if (!unicodes->has (cp) && !glyphs->has (gid))
+ continue;
+
+ 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;
@@ -330,25 +573,50 @@ _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));
+ }
+}
- cmap.fini ();
+#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.get_gid (),
+ gids_to_retain,
+ operation_count,
+ depth);
+
+ return operation_count;
}
static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
- bool close_over_gsub,
- bool close_over_gpos,
- bool close_over_gdef)
+ hb_set_t* drop_tables)
{
- OT::glyf::accelerator_t glyf;
+ OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF
- OT::cff1::accelerator_t cff;
-#endif
- glyf.init (plan->source);
-#ifndef HB_NO_SUBSET_CFF
- cff.init (plan->source);
+ OT::cff1::accelerator_t cff (plan->source);
#endif
plan->_glyphset_gsub->add (0); // Not-def
@@ -356,62 +624,86 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
#ifndef HB_NO_SUBSET_LAYOUT
- if (close_over_gsub)
+ if (!drop_tables->has (HB_OT_TAG_GSUB))
// closure all glyphs/lookups/features needed for GSUB substitutions.
- _closure_glyphs_lookups_features<OT::GSUB> (
- plan->source,
+ _closure_glyphs_lookups_features<GSUB> (
+ plan,
plan->_glyphset_gsub,
- plan->layout_features,
plan->gsub_lookups,
plan->gsub_features,
- plan->gsub_langsys);
+ plan->gsub_langsys,
+ plan->gsub_feature_record_cond_idx_map,
+ plan->gsub_feature_substitutes_map);
- if (close_over_gpos)
- _closure_glyphs_lookups_features<OT::GPOS> (
- plan->source,
+ if (!drop_tables->has (HB_OT_TAG_GPOS))
+ _closure_glyphs_lookups_features<GPOS> (
+ plan,
plan->_glyphset_gsub,
- plan->layout_features,
plan->gpos_lookups,
plan->gpos_features,
- plan->gpos_langsys);
+ plan->gpos_langsys,
+ plan->gpos_feature_record_cond_idx_map,
+ plan->gpos_feature_substitutes_map);
#endif
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
- _math_closure (plan->source, plan->_glyphset_mathed);
- _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+ if (!drop_tables->has (HB_OT_TAG_MATH))
+ {
+ _math_closure (plan, plan->_glyphset_mathed);
+ _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+ }
hb_set_t cur_glyphset = *plan->_glyphset_mathed;
- _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
- _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
-
- // Populate a full set of glyphs to retain by adding all referenced
- // composite glyphs.
- for (hb_codepoint_t gid : cur_glyphset.iter ())
+ if (!drop_tables->has (HB_OT_TAG_COLR))
{
- glyf.add_gid_and_children (gid, plan->_glyphset);
+ _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
+ _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. */
+ 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 (!plan->accelerator || plan->accelerator->has_seac)
+ {
+ bool has_seac = false;
if (cff.is_valid ())
- _add_cff_seac_components (cff, gid, plan->_glyphset);
-#endif
+ for (hb_codepoint_t gid : cur_glyphset)
+ if (_add_cff_seac_components (cff, gid, plan->_glyphset))
+ has_seac = true;
+ plan->has_seac = has_seac;
}
+#endif
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
#ifndef HB_NO_VAR
- if (close_over_gdef)
- _collect_layout_variation_indices (plan->source,
- plan->_glyphset_gsub,
- plan->gpos_lookups,
- plan->layout_variation_indices,
- plan->layout_variation_idx_map);
+ if (!drop_tables->has (HB_OT_TAG_GDEF))
+ _collect_layout_variation_indices (plan);
#endif
+}
-#ifndef HB_NO_SUBSET_CFF
- cff.fini ();
-#endif
- glyf.fini ();
+static void
+_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
+ const hb_map_t* glyph_map,
+ hb_map_t* out)
+{
+ + hb_iter (glyph_set_gsub)
+ | hb_map ([&] (hb_codepoint_t gid) {
+ return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid,
+ glyph_map->get (gid));
+ })
+ | hb_sink (out)
+ ;
}
static void
@@ -422,13 +714,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> (_, _);
@@ -436,10 +734,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;
}
@@ -451,18 +748,67 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
static void
_nameid_closure (hb_face_t *face,
- hb_set_t *nameids)
+ hb_set_t *nameids,
+ bool all_axes_pinned,
+ hb_hashmap_t<hb_tag_t, float> *user_axes_location)
{
#ifndef HB_NO_STYLE
- face->table.STAT->collect_name_ids (nameids);
+ face->table.STAT->collect_name_ids (user_axes_location, nameids);
#endif
#ifndef HB_NO_VAR
- face->table.fvar->collect_name_ids (nameids);
+ if (!all_axes_pinned)
+ face->table.fvar->collect_name_ids (user_axes_location, nameids);
#endif
}
+#ifndef HB_NO_VAR
+static void
+_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
+{
+ if (plan->user_axes_location->is_empty ())
+ return;
+
+ hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
+
+ bool has_avar = face->table.avar->has_data ();
+ const OT::SegmentMaps *seg_maps = nullptr;
+ if (has_avar)
+ seg_maps = face->table.avar->get_segment_maps ();
+
+ bool axis_not_pinned = false;
+ unsigned old_axis_idx = 0, new_axis_idx = 0;
+ for (const auto& axis : axes)
+ {
+ hb_tag_t axis_tag = axis.get_axis_tag ();
+ plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag);
+
+ if (!plan->user_axes_location->has (axis_tag))
+ {
+ axis_not_pinned = true;
+ plan->axes_index_map->set (old_axis_idx, new_axis_idx);
+ new_axis_idx++;
+ }
+ else
+ {
+ int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
+ if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
+ {
+ normalized_v = seg_maps->map (normalized_v);
+ }
+ plan->axes_location->set (axis_tag, normalized_v);
+ if (normalized_v != 0)
+ plan->pinned_at_default = false;
+ }
+ if (has_avar)
+ seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
+
+ old_axis_idx++;
+ }
+ plan->all_axes_pinned = !axis_not_pinned;
+}
+#endif
/**
- * hb_subset_plan_create:
+ * hb_subset_plan_create_or_fail:
* @face: font face to create the plan for.
* @input: a #hb_subset_input_t input.
*
@@ -471,25 +817,29 @@ _nameid_closure (hb_face_t *face,
* which tables and glyphs should be retained.
*
* Return value: (transfer full): New subset plan. Destroy with
- * hb_subset_plan_destroy().
+ * hb_subset_plan_destroy(). If there is a failure creating the plan
+ * nullptr will be returned.
*
- * Since: 1.7.5
+ * Since: 4.0.0
**/
hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t *face,
- const hb_subset_input_t *input)
+hb_subset_plan_create_or_fail (hb_face_t *face,
+ const hb_subset_input_t *input)
{
hb_subset_plan_t *plan;
if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
- return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
+ return nullptr;
plan->successful = true;
plan->flags = input->flags;
plan->unicodes = hb_set_create ();
+
+ plan->unicode_to_new_gid_list.init ();
+
plan->name_ids = hb_set_copy (input->sets.name_ids);
- _nameid_closure (face, plan->name_ids);
plan->name_languages = hb_set_copy (input->sets.name_languages);
plan->layout_features = hb_set_copy (input->sets.layout_features);
+ plan->layout_scripts = hb_set_copy (input->sets.layout_scripts);
plan->glyphs_requested = hb_set_copy (input->sets.glyphs);
plan->drop_tables = hb_set_copy (input->sets.drop_tables);
plan->no_subset_tables = hb_set_copy (input->sets.no_subset_tables);
@@ -499,34 +849,82 @@ hb_subset_plan_create (hb_face_t *face,
plan->_glyphset = hb_set_create ();
plan->_glyphset_gsub = hb_set_create ();
plan->_glyphset_mathed = hb_set_create ();
+ plan->_glyphset_colred = hb_set_create ();
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 ();
- if (plan->check_success (plan->gsub_langsys = hb_object_create<script_langsys_map> ()))
- plan->gsub_langsys->init_shallow ();
- if (plan->check_success (plan->gpos_langsys = hb_object_create<script_langsys_map> ()))
- plan->gpos_langsys->init_shallow ();
+ plan->check_success (plan->gsub_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
+ plan->check_success (plan->gpos_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
plan->gsub_features = hb_map_create ();
plan->gpos_features = hb_map_create ();
+
+ plan->check_success (plan->gsub_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+ plan->check_success (plan->gpos_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+
+ plan->check_success (plan->gsub_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+ plan->check_success (plan->gpos_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+
plan->colrv1_layers = hb_map_create ();
plan->colr_palettes = hb_map_create ();
- plan->layout_variation_indices = hb_set_create ();
- plan->layout_variation_idx_map = hb_map_create ();
+ plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+ plan->gdef_varstore_inner_maps.init ();
+
+ plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ());
+ plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ());
+ plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
+ if (plan->user_axes_location && input->axes_location)
+ *plan->user_axes_location = *input->axes_location;
+ plan->check_success (plan->axes_index_map = hb_map_create ());
+ plan->check_success (plan->axes_old_index_tag_map = hb_map_create ());
+ plan->all_axes_pinned = false;
+ plan->pinned_at_default = true;
+
+ plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+ plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
+
+#ifdef HB_EXPERIMENTAL_API
+ plan->check_success (plan->name_table_overrides = hb_hashmap_create<hb_ot_name_record_ids_t, hb_bytes_t> ());
+ if (plan->name_table_overrides && input->name_table_overrides)
+ {
+ for (auto _ : *input->name_table_overrides)
+ {
+ hb_bytes_t name_bytes = _.second;
+ unsigned len = name_bytes.length;
+ char *name_str = (char *) hb_malloc (len);
+ if (unlikely (!plan->check_success (name_str)))
+ break;
+
+ hb_memcpy (name_str, name_bytes.arrayZ, len);
+ plan->name_table_overrides->set (_.first, hb_bytes_t (name_str, len));
+ }
+ }
+#endif
+
+ void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
- if (plan->in_error ()) {
- return plan;
+ plan->attach_accelerator_data = input->attach_accelerator_data;
+ plan->force_long_loca = input->force_long_loca;
+ if (accel)
+ plan->accelerator = (hb_subset_accelerator_t*) accel;
+
+
+ if (unlikely (plan->in_error ())) {
+ hb_subset_plan_destroy (plan);
+ return nullptr;
}
+#ifndef HB_NO_VAR
+ _normalize_axes_location (face, plan);
+#endif
+
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
- _populate_gids_to_retain (plan,
- !input->sets.drop_tables->has (HB_OT_TAG_GSUB),
- !input->sets.drop_tables->has (HB_OT_TAG_GPOS),
- !input->sets.drop_tables->has (HB_OT_TAG_GDEF));
+ _populate_gids_to_retain (plan, input->sets.drop_tables);
_create_old_gid_to_new_gid_map (face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
@@ -535,6 +933,46 @@ hb_subset_plan_create (hb_face_t *face,
plan->reverse_glyph_map,
&plan->_num_output_glyphs);
+ _create_glyph_map_gsub (
+ plan->_glyphset_gsub,
+ plan->glyph_map,
+ plan->glyph_map_gsub);
+
+ // Now that we have old to new gid map update the unicode to new gid list.
+ for (unsigned i = 0; i < plan->unicode_to_new_gid_list.length; i++)
+ {
+ // Use raw array access for performance.
+ plan->unicode_to_new_gid_list.arrayZ[i].second =
+ plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second);
+ }
+
+ _nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location);
+ if (unlikely (plan->in_error ())) {
+ hb_subset_plan_destroy (plan);
+ return nullptr;
+ }
+
+
+ if (plan->attach_accelerator_data)
+ {
+ hb_multimap_t gid_to_unicodes;
+
+ hb_map_t &unicode_to_gid = *plan->codepoint_to_glyph;
+
+ for (auto unicode : *plan->unicodes)
+ {
+ auto gid = unicode_to_gid[unicode];
+ gid_to_unicodes.add (gid, unicode);
+ }
+
+ plan->inprogress_accelerator =
+ hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
+ gid_to_unicodes,
+ *plan->unicodes,
+ plan->has_seac);
+ }
+
+
return plan;
}
@@ -545,56 +983,125 @@ hb_subset_plan_create (hb_face_t *face,
* Decreases the reference count on @plan, and if it reaches zero, destroys
* @plan, freeing all memory.
*
- * Since: 1.7.5
+ * Since: 4.0.0
**/
void
hb_subset_plan_destroy (hb_subset_plan_t *plan)
{
if (!hb_object_destroy (plan)) return;
- hb_set_destroy (plan->unicodes);
- hb_set_destroy (plan->name_ids);
- hb_set_destroy (plan->name_languages);
- hb_set_destroy (plan->layout_features);
- hb_set_destroy (plan->glyphs_requested);
- hb_set_destroy (plan->drop_tables);
- hb_set_destroy (plan->no_subset_tables);
- hb_face_destroy (plan->source);
- hb_face_destroy (plan->dest);
- hb_map_destroy (plan->codepoint_to_glyph);
- hb_map_destroy (plan->glyph_map);
- hb_map_destroy (plan->reverse_glyph_map);
- hb_set_destroy (plan->_glyphset);
- hb_set_destroy (plan->_glyphset_gsub);
- hb_set_destroy (plan->_glyphset_mathed);
- hb_map_destroy (plan->gsub_lookups);
- hb_map_destroy (plan->gpos_lookups);
- hb_map_destroy (plan->gsub_features);
- hb_map_destroy (plan->gpos_features);
- hb_map_destroy (plan->colrv1_layers);
- hb_map_destroy (plan->colr_palettes);
- hb_set_destroy (plan->layout_variation_indices);
- hb_map_destroy (plan->layout_variation_idx_map);
-
- if (plan->gsub_langsys)
- {
- for (auto _ : plan->gsub_langsys->iter ())
- hb_set_destroy (_.second);
+ hb_free (plan);
+}
- hb_object_destroy (plan->gsub_langsys);
- plan->gsub_langsys->fini_shallow ();
- hb_free (plan->gsub_langsys);
- }
+/**
+ * hb_subset_plan_old_to_new_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the original font to glyphs in the
+ * subset that will be produced by @plan
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
+{
+ return plan->glyph_map;
+}
- if (plan->gpos_langsys)
- {
- for (auto _ : plan->gpos_langsys->iter ())
- hb_set_destroy (_.second);
+/**
+ * hb_subset_plan_new_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the subset that will be produced by
+ * @plan and the glyph in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+ return plan->reverse_glyph_map;
+}
- hb_object_destroy (plan->gpos_langsys);
- plan->gpos_langsys->fini_shallow ();
- hb_free (plan->gpos_langsys);
- }
+/**
+ * hb_subset_plan_unicode_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between codepoints in the original font and the
+ * associated glyph id in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+ return plan->codepoint_to_glyph;
+}
- hb_free (plan);
+/**
+ * hb_subset_plan_reference: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ *
+ * Increases the reference count on @plan.
+ *
+ * Return value: @plan.
+ *
+ * Since: 4.0.0
+ **/
+hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan)
+{
+ return hb_object_reference (plan);
+}
+
+/**
+ * hb_subset_plan_set_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to set
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the given subset plan object.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 4.0.0
+ **/
+hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t *plan,
+ hb_user_data_key_t *key,
+ void *data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+{
+ return hb_object_set_user_data (plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_subset_plan_get_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to query
+ *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified subset plan object.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 4.0.0
+ **/
+void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+ hb_user_data_key_t *key)
+{
+ return hb_object_get_user_data (plan, key);
}
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index c30feeb42..1b2aee782 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -31,19 +31,91 @@
#include "hb-subset.h"
#include "hb-subset-input.hh"
+#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
+#include "hb-bimap.hh"
#include "hb-set.hh"
+namespace OT {
+struct Feature;
+}
+
struct hb_subset_plan_t
{
+ hb_subset_plan_t ()
+ {}
+
+ ~hb_subset_plan_t()
+ {
+ hb_set_destroy (unicodes);
+ hb_set_destroy (name_ids);
+ hb_set_destroy (name_languages);
+ hb_set_destroy (layout_features);
+ hb_set_destroy (layout_scripts);
+ hb_set_destroy (glyphs_requested);
+ hb_set_destroy (drop_tables);
+ hb_set_destroy (no_subset_tables);
+ hb_face_destroy (source);
+ hb_face_destroy (dest);
+ hb_map_destroy (codepoint_to_glyph);
+ hb_map_destroy (glyph_map);
+ hb_map_destroy (reverse_glyph_map);
+ hb_map_destroy (glyph_map_gsub);
+ hb_set_destroy (_glyphset);
+ hb_set_destroy (_glyphset_gsub);
+ hb_set_destroy (_glyphset_mathed);
+ hb_set_destroy (_glyphset_colred);
+ hb_map_destroy (gsub_lookups);
+ hb_map_destroy (gpos_lookups);
+ hb_map_destroy (gsub_features);
+ hb_map_destroy (gpos_features);
+ hb_map_destroy (colrv1_layers);
+ hb_map_destroy (colr_palettes);
+ hb_map_destroy (axes_index_map);
+ hb_map_destroy (axes_old_index_tag_map);
+
+ hb_hashmap_destroy (gsub_langsys);
+ hb_hashmap_destroy (gpos_langsys);
+ hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
+ hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
+ hb_hashmap_destroy (gsub_feature_substitutes_map);
+ hb_hashmap_destroy (gpos_feature_substitutes_map);
+ hb_hashmap_destroy (axes_location);
+ hb_hashmap_destroy (sanitized_table_cache);
+ hb_hashmap_destroy (hmtx_map);
+ hb_hashmap_destroy (vmtx_map);
+ hb_hashmap_destroy (layout_variation_idx_delta_map);
+
+#ifdef HB_EXPERIMENTAL_API
+ if (name_table_overrides)
+ {
+ for (auto _ : *name_table_overrides)
+ _.second.fini ();
+ }
+ hb_hashmap_destroy (name_table_overrides);
+#endif
+
+ if (inprogress_accelerator)
+ hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
+
+ if (user_axes_location)
+ {
+ hb_object_destroy (user_axes_location);
+ hb_free (user_axes_location);
+ }
+ }
+
hb_object_header_t header;
bool successful;
unsigned flags;
+ bool attach_accelerator_data = false;
+ bool force_long_loca = false;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
+ hb_sorted_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;
@@ -54,6 +126,9 @@ struct hb_subset_plan_t
//layout features which will be preserved
hb_set_t *layout_features;
+ // layout scripts which will be preserved.
+ hb_set_t *layout_scripts;
+
//glyph ids requested to retain
hb_set_t *glyphs_requested;
@@ -69,6 +144,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;
@@ -78,30 +154,89 @@ struct hb_subset_plan_t
hb_set_t *_glyphset;
hb_set_t *_glyphset_gsub;
hb_set_t *_glyphset_mathed;
+ hb_set_t *_glyphset_colred;
//active lookups we'd like to retain
hb_map_t *gsub_lookups;
hb_map_t *gpos_lookups;
//active langsys we'd like to retain
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gsub_langsys;
- hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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;
hb_map_t *gpos_features;
+ //active feature variation records/condition index with variations
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
+
+ //feature index-> address of substituation feature table mapping with
+ //variations
+ hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
+ hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
+
//active layers/palettes we'd like to retain
hb_map_t *colrv1_layers;
hb_map_t *colr_palettes;
- //The set of layout item variation store delta set indices to be retained
- hb_set_t *layout_variation_indices;
- //Old -> New layout item variation store delta set index mapping
- hb_map_t *layout_variation_idx_map;
+ //Old layout item variation index -> (New varidx, delta) mapping
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
+
+ //gdef varstore retained varidx mapping
+ hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps;
+
+ hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
+ //normalized axes location map
+ hb_hashmap_t<hb_tag_t, int> *axes_location;
+ //user specified axes location map
+ hb_hashmap_t<hb_tag_t, float> *user_axes_location;
+ //retained old axis index -> new axis index mapping in fvar axis array
+ hb_map_t *axes_index_map;
+ //axis_index->axis_tag mapping in fvar axis array
+ hb_map_t *axes_old_index_tag_map;
+ bool all_axes_pinned;
+ bool pinned_at_default;
+ bool has_seac;
+
+ //hmtx metrics map: new gid->(advance, lsb)
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map;
+ //vmtx metrics map: new gid->(advance, lsb)
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
+
+#ifdef HB_EXPERIMENTAL_API
+ // name table overrides map: hb_ot_name_record_ids_t-> name string new value or
+ // None to indicate should remove
+ hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides;
+#endif
+
+ const hb_subset_accelerator_t* accelerator;
+ hb_subset_accelerator_t* inprogress_accelerator;
public:
+ template<typename T>
+ hb_blob_ptr_t<T> source_table()
+ {
+ hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
+
+ auto *cache = accelerator ? &accelerator->sanitized_table_cache : sanitized_table_cache;
+ if (cache
+ && !cache->in_error ()
+ && cache->has (+T::tableTag)) {
+ return hb_blob_reference (cache->get (+T::tableTag).get ());
+ }
+
+ hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
+ hb_blob_t* ret = hb_blob_reference (table_blob.get ());
+
+ if (likely (cache))
+ cache->set (+T::tableTag, std::move (table_blob));
+
+ return ret;
+ }
+
bool in_error () const { return !successful; }
bool check_success(bool success)
@@ -197,13 +332,4 @@ struct hb_subset_plan_t
}
};
-typedef struct hb_subset_plan_t hb_subset_plan_t;
-
-HB_INTERNAL hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t *face,
- const hb_subset_input_t *input);
-
-HB_INTERNAL void
-hb_subset_plan_destroy (hb_subset_plan_t *plan);
-
#endif /* HB_SUBSET_PLAN_HH */
diff --git a/src/hb-subset-repacker.cc b/src/hb-subset-repacker.cc
new file mode 100644
index 000000000..55ca48d70
--- /dev/null
+++ b/src/hb-subset-repacker.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+#include "hb-repacker.hh"
+
+#ifdef HB_EXPERIMENTAL_API
+
+/**
+ * hb_subset_repack_or_fail:
+ * @table_tag: tag of the table being packed, needed to allow table specific optimizations.
+ * @hb_objects: raw array of struct hb_object_t, which provides
+ * object graph info
+ * @num_hb_objs: number of hb_object_t in the hb_objects array.
+ *
+ * Given the input object graph info, repack a table to eliminate
+ * offset overflows. A nullptr is returned if the repacking attempt fails.
+ * Table specific optimizations (eg. extension promotion in GSUB/GPOS) may be performed.
+ * Passing HB_TAG_NONE will disable table specific optimizations.
+ *
+ * Since: EXPERIMENTAL
+ **/
+hb_blob_t* hb_subset_repack_or_fail (hb_tag_t table_tag,
+ hb_object_t* hb_objects,
+ unsigned num_hb_objs)
+{
+ hb_vector_t<const hb_object_t *> packed;
+ packed.alloc (num_hb_objs + 1);
+ packed.push (nullptr);
+ for (unsigned i = 0 ; i < num_hb_objs ; i++)
+ packed.push (&(hb_objects[i]));
+
+ return hb_resolve_overflows (packed,
+ table_tag,
+ 20,
+ true);
+}
+#endif
diff --git a/src/hb-subset-repacker.h b/src/hb-subset-repacker.h
new file mode 100644
index 000000000..245cf6076
--- /dev/null
+++ b/src/hb-subset-repacker.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#ifndef HB_SUBSET_REPACKER_H
+#define HB_SUBSET_REPACKER_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+#ifdef HB_EXPERIMENTAL_API
+/*
+ * struct hb_link_t
+ * width: offsetSize in bytes
+ * position: position of the offset field in bytes
+ * from beginning of subtable
+ * objidx: index of subtable
+ */
+struct hb_link_t
+{
+ unsigned width;
+ unsigned position;
+ unsigned objidx;
+};
+
+typedef struct hb_link_t hb_link_t;
+
+/*
+ * struct hb_object_t
+ * head: start of object data
+ * tail: end of object data
+ * num_real_links: num of offset field in the object
+ * real_links: pointer to array of offset info
+ * num_virtual_links: num of objects that must be packed
+ * after current object in the final serialized order
+ * virtual_links: array of virtual link info
+ */
+struct hb_object_t
+{
+ char *head;
+ char *tail;
+ unsigned num_real_links;
+ hb_link_t *real_links;
+ unsigned num_virtual_links;
+ hb_link_t *virtual_links;
+};
+
+typedef struct hb_object_t hb_object_t;
+
+HB_EXTERN hb_blob_t*
+hb_subset_repack_or_fail (hb_tag_t table_tag,
+ hb_object_t* hb_objects,
+ unsigned num_hb_objs);
+
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_SUBSET_REPACKER_H */
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 048bdf188..186b12dbb 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -50,10 +50,16 @@
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-gvar-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-math-table.hh"
+#include "hb-ot-stat-table.hh"
#include "hb-repacker.hh"
+#include "hb-subset-accelerator.hh"
+
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
/**
* SECTION:hb-subset
@@ -76,13 +82,121 @@
* retain glyph ids option and configure the subset to pass through the layout tables untouched.
*/
+
+hb_user_data_key_t _hb_subset_accelerator_user_data_key = {};
+
+
+/*
+ * 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));
@@ -104,20 +218,16 @@ _repack (hb_tag_t tag, const hb_serialize_context_t& c)
if (!c.offset_overflow ())
return c.copy_blob ();
- hb_vector_t<char> buf;
- int buf_size = c.end - c.start;
- if (unlikely (!buf.alloc (buf_size)))
- return nullptr;
-
- hb_serialize_context_t repacked ((void *) buf, buf_size);
- hb_resolve_overflows (c.object_graph (), tag, &repacked);
+ hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag);
- if (unlikely (repacked.in_error ()))
- // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset
- // portion.
+ if (unlikely (!result))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.",
+ HB_UNTAG (tag));
return nullptr;
+ }
- return repacked.copy_blob ();
+ return result;
}
template<typename TableType>
@@ -125,7 +235,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> ();
@@ -138,57 +247,66 @@ _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);
- if (unlikely (!buf->alloc (buf_size)))
+ if (unlikely (buf_size > c->source_blob->length * 16 ||
+ !buf->alloc (buf_size)))
{
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
HB_UNTAG (c->table_tag), buf_size);
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> ();
+ hb_blob_ptr_t<TableType> source_blob = plan->source_table<TableType> ();
+ const TableType *table = source_blob.get ();
hb_tag_t tag = TableType::tableTag;
- if (!source_blob->data)
+ if (!source_blob.get_blob()->data)
{
DEBUG_MSG (SUBSET, nullptr,
"OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
- hb_blob_destroy (source_blob);
+ source_blob.destroy ();
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.get_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)))
{
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
- hb_blob_destroy (source_blob);
+ source_blob.destroy ();
return false;
}
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);
+ hb_subset_context_t c (source_blob.get_blob (), plan, &serializer, tag);
+ needed = _try_subset (table, &buf, &c);
}
- hb_blob_destroy (source_blob);
+ source_blob.destroy ();
if (serializer.in_error () && !serializer.only_offset_overflow ())
{
@@ -221,9 +339,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)
@@ -242,6 +368,8 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
switch (tag)
{
case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
+ return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+
case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */
case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */
case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
@@ -261,6 +389,14 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
return true;
#endif
+ case HB_TAG ('a','v','a','r'):
+ case HB_TAG ('f','v','a','r'):
+ case HB_TAG ('g','v','a','r'):
+ case HB_OT_TAG_HVAR:
+ case HB_OT_TAG_VVAR:
+ case HB_TAG ('M','V','A','R'):
+ return plan->all_axes_pinned;
+
default:
return false;
}
@@ -276,7 +412,24 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
}
static bool
-_subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
+_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
+ const hb_set_t &subsetted_tags,
+ const hb_set_t &pending_subset_tags)
+{
+ switch (tag)
+ {
+ case HB_OT_TAG_hmtx:
+ case HB_OT_TAG_vmtx:
+ return plan->pinned_at_default || !pending_subset_tags.has (HB_OT_TAG_glyf);
+ default:
+ return true;
+ }
+}
+
+static bool
+_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);
@@ -285,43 +438,51 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag));
switch (tag)
{
- case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan);
- case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan);
- case HB_OT_TAG_name: return _subset<const OT::name> (plan);
+ case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf);
+ case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf);
+ case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf);
case HB_OT_TAG_head:
if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf))
return true; /* skip head, handled by glyf */
- return _subset<const OT::head> (plan);
+ return _subset<const OT::head> (plan, buf);
case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */
- case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan);
+ case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf);
case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */
- case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan);
- case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan);
- case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan);
+ case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf);
+ case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf);
+ case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf);
case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */
- case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan);
- case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
- case HB_OT_TAG_post: return _subset<const OT::post> (plan);
- case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
- case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan);
- case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
+ case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf);
+ case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf);
+ case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf);
+ case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf);
+ case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf);
+ case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
- case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan);
+ case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
#ifndef HB_NO_SUBSET_CFF
- case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan);
- case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan);
- case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan);
+ case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf);
+ case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf);
+ case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf);
#endif
#ifndef HB_NO_SUBSET_LAYOUT
- case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
- case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan);
- case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
- case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
- case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);
- case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan);
+ case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf);
+ case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf);
+ case HB_OT_TAG_GPOS: return _subset<const 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
+ case HB_OT_TAG_fvar:
+ if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
+ return _subset<const OT::fvar> (plan, buf);
+ case HB_OT_TAG_STAT:
+ /*TODO(qxliu): change the condition as we support more complex
+ * instancing operation*/
+ if (plan->all_axes_pinned) return _subset<const OT::STAT> (plan, buf);
+ else return _passthrough (plan, tag);
default:
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
@@ -332,6 +493,34 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
}
}
+static void _attach_accelerator_data (hb_subset_plan_t* plan,
+ hb_face_t* face /* IN/OUT */)
+{
+ if (!plan->inprogress_accelerator) return;
+
+ // Transfer the accelerator from the plan to us.
+ hb_subset_accelerator_t* accel = plan->inprogress_accelerator;
+ plan->inprogress_accelerator = nullptr;
+
+ if (accel->in_error ())
+ {
+ hb_subset_accelerator_t::destroy (accel);
+ return;
+ }
+
+ // Populate caches that need access to the final tables.
+ hb_blob_ptr_t<OT::cmap> cmap_ptr (hb_sanitize_context_t ().reference_table<OT::cmap> (face));
+ accel->cmap_cache = OT::cmap::create_filled_cache (cmap_ptr);
+ accel->destroy_cmap_cache = OT::SubtableUnicodesCache::destroy;
+
+ if (!hb_face_set_user_data(face,
+ hb_subset_accelerator_t::user_data_key(),
+ accel,
+ hb_subset_accelerator_t::destroy,
+ true))
+ hb_subset_accelerator_t::destroy (accel);
+}
+
/**
* hb_subset_or_fail:
* @source: font face data to be subset.
@@ -347,32 +536,99 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
{
if (unlikely (!input || !source)) return hb_face_get_empty ();
- hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
- if (unlikely (plan->in_error ())) {
- hb_subset_plan_destroy (plan);
+ hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input);
+ if (unlikely (!plan)) {
+ return nullptr;
+ }
+
+ hb_face_t * result = hb_subset_plan_execute_or_fail (plan);
+ hb_subset_plan_destroy (plan);
+ return result;
+}
+
+
+/**
+ * hb_subset_plan_execute_or_fail:
+ * @plan: a subsetting plan.
+ *
+ * Executes the provided subsetting @plan.
+ *
+ * Return value:
+ * on success returns a reference to generated font subset. If the subsetting operation fails
+ * returns nullptr.
+ *
+ * Since: 4.0.0
+ **/
+hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
+{
+ if (unlikely (!plan || plan->in_error ())) {
return nullptr;
}
- hb_set_t tags_set;
- bool success = true;
hb_tag_t table_tags[32];
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
- while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+
+ hb_set_t subsetted_tags, pending_subset_tags;
+ 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);
- if (unlikely (!success)) goto end;
+ if (_should_drop_table (plan, tag)) continue;
+ pending_subset_tags.add (tag);
}
+
offset += num_tables;
}
-end:
- hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
+ hb_vector_t<char> buf;
+ buf.alloc (4096 - 16);
+
- hb_subset_plan_destroy (plan);
- return result;
+ bool success = true;
+
+ while (!pending_subset_tags.is_empty ())
+ {
+ if (subsetted_tags.in_error ()
+ || pending_subset_tags.in_error ()) {
+ success = false;
+ goto end;
+ }
+
+ bool made_changes = false;
+ for (hb_tag_t tag : pending_subset_tags)
+ {
+ if (!_dependencies_satisfied (plan, tag,
+ subsetted_tags,
+ pending_subset_tags))
+ {
+ // delayed subsetting for some tables since they might have dependency on other tables
+ // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
+ // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
+ continue;
+ }
+
+ pending_subset_tags.del (tag);
+ subsetted_tags.add (tag);
+ made_changes = true;
+
+ success = _subset_table (plan, buf, tag);
+ if (unlikely (!success)) goto end;
+ }
+
+ if (!made_changes)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
+ success = false;
+ goto end;
+ }
+ }
+
+ if (success && plan->attach_accelerator_data) {
+ _attach_accelerator_data (plan, plan->dest);
+ }
+
+end:
+ return success ? hb_face_reference (plan->dest) : nullptr;
}
diff --git a/src/hb-subset.h b/src/hb-subset.h
index 1c65a4da1..b83264ea5 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -28,6 +28,7 @@
#define HB_SUBSET_H
#include "hb.h"
+#include "hb-ot.h"
HB_BEGIN_DECLS
@@ -40,6 +41,15 @@ HB_BEGIN_DECLS
typedef struct hb_subset_input_t hb_subset_input_t;
/**
+ * hb_subset_plan_t:
+ *
+ * Contains information about how the subset operation will be executed.
+ * Such as mappings from the old glyph ids to the new ones in the subset.
+ */
+
+typedef struct hb_subset_plan_t hb_subset_plan_t;
+
+/**
* hb_subset_flags_t:
* @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false.
* @HB_SUBSET_FLAGS_NO_HINTING: If set hinting instructions will be dropped in
@@ -61,6 +71,14 @@ typedef struct hb_subset_input_t hb_subset_input_t;
* in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified
+ * to produce a subset that is better suited to patching. For example cmap
+ * subtable format will be kept stable.
+ * @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final
+ * glyf table bytes. The table directory will include and entry as if the table was
+ * there but the actual final font blob will be truncated prior to the glyf data. This
+ * is a useful performance optimization when a font aware binary patching algorithm
+ * is being used to diff two subsets.
*
* List of boolean properties that can be configured on the subset input.
*
@@ -77,6 +95,8 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
+ // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u,
+ // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000400u,
} hb_subset_flags_t;
/**
@@ -91,6 +111,8 @@ typedef enum { /*< flags >*/
* @HB_SUBSET_SETS_NAME_LANG_ID: the set of name lang ids that will be retained.
* @HB_SUBSET_SETS_LAYOUT_FEATURE_TAG: the set of layout feature tags that will be retained
* in the subset.
+ * @HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG: the set of layout script tags that will be retained
+ * in the subset. Defaults to all tags. Since: 5.0.0
*
* List of sets that can be configured on the subset input.
*
@@ -104,6 +126,7 @@ typedef enum {
HB_SUBSET_SETS_NAME_ID,
HB_SUBSET_SETS_NAME_LANG_ID,
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+ HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
} hb_subset_sets_t;
HB_EXTERN hb_subset_input_t *
@@ -124,7 +147,7 @@ hb_subset_input_set_user_data (hb_subset_input_t *input,
HB_EXTERN void *
hb_subset_input_get_user_data (const hb_subset_input_t *input,
- hb_user_data_key_t *key);
+ hb_user_data_key_t *key);
HB_EXTERN hb_set_t *
hb_subset_input_unicode_set (hb_subset_input_t *input);
@@ -142,9 +165,70 @@ HB_EXTERN void
hb_subset_input_set_flags (hb_subset_input_t *input,
unsigned value);
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_value);
+
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t *input,
+ hb_ot_name_id_t name_id,
+ unsigned platform_id,
+ unsigned encoding_id,
+ unsigned language_id,
+ const char *name_str,
+ int str_len);
+
+#endif
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source);
+
HB_EXTERN hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
+HB_EXTERN hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_create_or_fail (hb_face_t *face,
+ const hb_subset_input_t *input);
+
+HB_EXTERN void
+hb_subset_plan_destroy (hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t *plan,
+ hb_user_data_key_t *key,
+ void *data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+HB_EXTERN void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+ hb_user_data_key_t *key);
+
+
HB_END_DECLS
#endif /* HB_SUBSET_H */
diff --git a/src/hb-ucd-table.hh b/src/hb-ucd-table.hh
index 1a4c89c17..f7d76eee1 100644
--- a/src/hb-ucd-table.hh
+++ b/src/hb-ucd-table.hh
@@ -4,7 +4,7 @@
*
* ./gen-ucd-table.py ucd.nounihan.grouped.xml
*
- * on file with this description: Unicode 14.0.0
+ * on file with this description: Unicode 15.0.0
*/
#ifndef 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[165] =
{
HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED,
HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC,
@@ -96,6 +96,8 @@ _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, HB_SCRIPT_KAWI,
+ HB_SCRIPT_NAG_MUNDARI,
};
static const uint16_t
_hb_ucd_dm1_p0_map[825] =
@@ -1067,2081 +1069,1128 @@ _hb_ucd_dm2_u64_map[388] =
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-_hb_ucd_u8[33120] =
+_hb_ucd_u8[17868] =
{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- 26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 58, 58, 58, 58, 58,
- 58, 58, 26, 61, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 26, 62, 58, 63, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 64, 26, 26, 65, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 66, 67, 68, 58, 58, 58, 58, 69, 58,
- 58, 58, 58, 58, 58, 58, 58, 70, 71, 72, 73, 74, 75, 76, 58, 77,
- 78, 79, 58, 80, 81, 58, 82, 83, 84, 85, 75, 86, 87, 88, 58, 58,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 89, 26, 26, 26, 26, 26, 26, 26, 90, 91, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 92, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 93, 58, 58, 58, 58, 58, 58, 26, 94, 58, 58,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 95, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 96, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 97,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 98,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21,
- 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 21, 18, 24, 16,
- 24, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 0,
- 29, 21, 23, 23, 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24,
- 26, 25, 15, 15, 24, 5, 21, 21, 24, 15, 7, 19, 15, 15, 15, 21,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, 9, 9, 9, 9, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9,
- 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 9, 5, 5,
- 5, 9, 9, 5, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 9, 9,
- 9, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 5, 9, 9, 5, 9,
- 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 5, 9, 5, 9, 9,
- 5, 9, 9, 9, 5, 9, 5, 9, 9, 5, 5, 7, 9, 5, 5, 5,
- 7, 7, 7, 7, 9, 8, 5, 9, 8, 5, 9, 8, 5, 9, 5, 9,
- 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5,
- 5, 9, 8, 5, 9, 5, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 9, 9, 5, 9, 9, 5,
- 5, 9, 5, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 6, 6, 6, 6, 6, 24, 24, 24, 24, 24, 24, 24, 6, 24, 6, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 9, 5, 9, 5, 6, 24, 9, 5, 2, 2, 6, 5, 5, 5, 21, 9,
- 2, 2, 2, 2, 24, 24, 9, 21, 9, 9, 9, 2, 9, 2, 9, 9,
- 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9,
- 5, 5, 9, 9, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 5, 5, 9, 5, 25, 9, 5, 9, 9, 5, 5, 9, 9, 9,
- 9, 5, 26, 12, 12, 12, 12, 12, 11, 11, 9, 5, 9, 5, 9, 5,
- 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5,
- 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 2, 2, 6, 21, 21, 21, 21, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 17, 2, 2, 26, 26, 23,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12,
- 21, 12, 12, 21, 12, 12, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 22, 22, 22, 24, 7, 7,
+ 25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7,
- 7, 7, 7, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 1, 21, 21, 21,
- 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 7, 7,
- 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 21, 7, 12, 12, 12, 12, 12, 12, 12, 1, 26, 12,
- 12, 12, 12, 12, 12, 6, 6, 12, 12, 26, 12, 12, 12, 12, 7, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 26, 26, 7,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 1,
- 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 6, 6, 26, 21, 21, 21, 6, 2, 2, 12, 23, 23,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 6, 12, 12, 12, 6, 12, 12, 12, 12, 12, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 2, 2, 21, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 24, 7, 7, 7, 7, 7, 7, 2,
- 1, 1, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 12, 12, 12, 12, 12, 12,
- 12, 12, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10,
- 7, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 21, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 2, 7, 2, 2, 2, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 7, 2,
- 2, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 7, 7, 2, 7,
- 7, 7, 12, 12, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 7, 7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23, 7, 21, 12, 2,
- 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 2, 7, 7, 2, 2, 12, 2, 10, 10,
- 10, 12, 12, 2, 2, 2, 2, 12, 12, 2, 2, 12, 12, 12, 2, 2,
- 2, 12, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 2, 7, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 12, 7, 7, 7, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7,
- 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 12, 2, 12, 12, 10, 2, 10, 10, 12, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 23, 2, 2, 2, 2, 2, 2, 2, 7, 12, 12, 12, 12, 12, 12,
- 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12,
- 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 2, 2,
- 2, 2, 2, 2, 2, 12, 12, 10, 2, 2, 2, 2, 7, 7, 2, 7,
- 26, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 12, 7, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7,
- 7, 2, 7, 7, 7, 7, 2, 2, 2, 7, 7, 2, 7, 2, 7, 7,
- 2, 2, 2, 7, 7, 2, 2, 2, 7, 7, 7, 2, 2, 2, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 10, 10,
- 12, 10, 10, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 12, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26, 2, 2, 2, 2, 2,
- 12, 10, 10, 10, 12, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 7, 12, 12,
- 12, 10, 10, 10, 10, 2, 12, 12, 12, 2, 12, 12, 12, 12, 2, 2,
- 2, 2, 2, 2, 2, 12, 12, 2, 7, 7, 7, 2, 2, 7, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 21, 15, 15, 15, 15, 15, 15, 15, 26,
- 7, 12, 10, 10, 21, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12,
- 10, 10, 10, 10, 10, 2, 12, 10, 10, 2, 10, 10, 12, 12, 2, 2,
- 2, 2, 2, 2, 2, 10, 10, 2, 2, 2, 2, 2, 2, 7, 7, 2,
- 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 2, 10, 10, 10, 2, 10, 10, 10, 12, 7, 26,
- 2, 2, 2, 2, 7, 7, 7, 10, 15, 15, 15, 15, 15, 15, 15, 7,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 7, 7, 7, 7, 7, 7,
- 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 12, 2, 2, 2, 2, 10,
- 10, 10, 12, 12, 12, 2, 12, 2, 10, 10, 10, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 23,
- 7, 7, 7, 7, 7, 7, 6, 12, 12, 12, 12, 12, 12, 12, 12, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7,
- 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 2, 2,
- 7, 7, 7, 7, 7, 2, 6, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 7, 7, 7, 7,
- 7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
- 12, 12, 12, 12, 12, 21, 12, 12, 7, 7, 7, 7, 7, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 26, 26,
- 26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 2, 26, 26,
- 21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 12,
- 12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21,
- 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 7, 7, 7, 7, 12, 12,
- 12, 7, 10, 10, 10, 7, 7, 10, 10, 10, 10, 10, 10, 10, 7, 7,
- 7, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12, 7, 10,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26,
- 9, 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 2, 2, 9, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 6, 5, 5, 5,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 2,
- 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 2,
- 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2,
- 17, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 26, 21, 7,
- 29, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22, 18, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 21, 21, 14, 14,
- 14, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 12, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7,
- 7, 7, 12, 12, 10, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 2, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10,
- 10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 21, 21, 21, 6, 21, 21, 21, 23, 7, 12, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12, 1, 12,
- 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 7, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2,
- 12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10, 2, 2, 2, 2,
- 10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12, 2, 2, 2, 2,
- 26, 2, 2, 2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2,
- 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 2, 2, 2, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 10, 10, 12, 2, 2, 21, 21,
- 7, 7, 7, 7, 7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12, 2,
- 12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12,
- 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2,
- 12, 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10,
- 10, 10, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2,
- 21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 21, 21, 2,
- 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12, 7, 7,
- 7, 7, 7, 7, 7, 7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12,
- 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21,
- 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
- 12, 12, 12, 12, 10, 10, 12, 12, 2, 2, 2, 21, 21, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9,
- 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 10, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 12, 7, 7,
- 7, 7, 7, 7, 12, 7, 7, 10, 12, 12, 7, 2, 2, 2, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
- 9, 5, 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9,
- 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 2, 9, 2, 9, 2, 9, 2, 9,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 8, 8,
- 5, 5, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 5, 24,
- 24, 24, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 24,
- 5, 5, 5, 5, 2, 2, 5, 5, 9, 9, 9, 9, 2, 24, 24, 24,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 24, 24, 24,
- 2, 2, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 2,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1,
- 17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20,
- 21, 21, 21, 21, 21, 21, 21, 21, 27, 28, 1, 1, 1, 1, 1, 29,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16,
- 16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29,
- 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 15, 6, 2, 2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 6,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 2,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
- 11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 9, 26, 26, 26, 26, 9, 26, 26, 5, 9, 9, 9, 5, 5,
- 9, 9, 9, 5, 26, 9, 26, 26, 25, 9, 9, 9, 9, 9, 26, 26,
- 26, 26, 26, 26, 9, 26, 9, 26, 9, 26, 9, 9, 9, 9, 26, 5,
- 9, 9, 9, 9, 5, 7, 7, 7, 7, 5, 26, 26, 5, 5, 9, 9,
- 25, 25, 25, 25, 25, 9, 5, 5, 5, 5, 26, 25, 26, 26, 5, 26,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 9, 5, 14, 14, 14, 14, 15, 26, 26, 2, 2, 2, 2,
- 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26,
- 25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25,
- 26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26,
- 25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25,
- 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15,
- 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18,
- 22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18,
- 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
- 18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25,
- 25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26,
- 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 9, 5, 9, 9, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9,
- 9, 5, 9, 5, 5, 9, 5, 5, 5, 5, 5, 5, 6, 6, 9, 9,
- 9, 5, 9, 5, 5, 26, 26, 26, 26, 26, 26, 9, 5, 9, 5, 12,
- 12, 12, 9, 5, 2, 2, 2, 2, 2, 21, 21, 21, 21, 15, 21, 21,
- 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 2, 2, 5, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 6,
- 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 2,
- 21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21,
- 20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21, 6,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21,
- 17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 26, 26, 21, 21, 21, 22, 18, 22, 18, 22, 18, 22, 18, 17, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2,
- 29, 21, 21, 21, 26, 6, 7, 14, 22, 18, 22, 18, 22, 18, 22, 18,
- 22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18,
- 26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10,
- 17, 6, 6, 6, 6, 6, 26, 26, 14, 14, 14, 6, 7, 21, 26, 26,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 24, 24, 6, 6, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 6, 6, 6, 7,
- 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15,
- 26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 2, 2, 2, 2,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 7, 12,
- 11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 6,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 6, 6, 12, 12,
- 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 12, 12, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 24, 24, 24, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 24, 24, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 6, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5, 9, 5, 9, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 6, 24, 24, 9, 5, 9, 5, 7,
- 9, 5, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, 9, 9, 5,
- 9, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 9, 9, 9, 5, 9, 5, 2, 2, 2, 2, 2,
- 9, 5, 2, 5, 2, 5, 9, 5, 9, 5, 2, 2, 2, 2, 2, 2,
- 2, 2, 6, 6, 6, 9, 5, 7, 6, 6, 5, 7, 7, 7, 7, 7,
- 7, 7, 12, 7, 7, 7, 12, 7, 7, 7, 7, 12, 7, 7, 7, 7,
- 7, 7, 7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 26, 26, 23, 26, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21,
- 12, 12, 7, 7, 7, 7, 7, 7, 21, 21, 21, 7, 21, 7, 7, 12,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 7, 7, 7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10,
- 10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 6,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 21, 21,
- 7, 7, 7, 7, 7, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 10,
- 10, 12, 12, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 21, 21, 21, 21,
- 6, 7, 7, 7, 7, 7, 7, 26, 26, 26, 7, 10, 12, 10, 7, 7,
- 12, 7, 12, 12, 12, 7, 7, 12, 12, 7, 7, 7, 7, 7, 12, 12,
- 7, 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, 21, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 12, 12, 10, 10,
- 21, 21, 7, 6, 6, 10, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 2,
- 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 6, 6, 6, 6,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 24, 24, 2, 2, 2, 2,
- 7, 7, 7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12, 2, 2,
- 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 7, 12, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 25, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 2,
- 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 18, 22,
- 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 26,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 23, 26, 26, 26,
- 21, 21, 21, 21, 21, 21, 21, 22, 18, 21, 2, 2, 2, 2, 2, 2,
- 21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
- 18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16,
- 21, 21, 21, 2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21,
- 21, 21, 25, 17, 25, 25, 25, 2, 21, 23, 21, 21, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 1,
- 2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 22,
- 18, 21, 22, 18, 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6,
- 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7,
- 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 2, 2, 2,
- 23, 23, 25, 24, 26, 23, 23, 2, 26, 25, 25, 25, 25, 26, 26, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 26, 26, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7,
- 21, 21, 21, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2,
- 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 2, 2,
- 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2,
- 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7,
- 7, 14, 7, 7, 7, 7, 7, 7, 7, 7, 14, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 21,
- 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 21, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 9, 9, 9, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 2, 9, 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 2, 2, 2,
- 6, 6, 6, 6, 6, 6, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 2, 2, 7, 2, 2, 7,
- 7, 7, 7, 7, 7, 7, 2, 21, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 7, 26, 26, 15, 15, 15, 15, 15, 15, 15,
- 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 2, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 15, 15, 7, 7,
- 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 12, 12, 12, 2, 12, 12, 2, 2, 2, 2, 2, 12, 12, 12, 12,
- 7, 7, 7, 7, 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12, 2, 2, 2, 2, 12,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 7, 7, 26, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 12, 12, 2, 2, 2, 2, 15, 15, 15, 15, 15,
- 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 7, 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15,
- 9, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 12, 12, 17, 2, 2,
- 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 15, 15, 15, 15, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 12, 12, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2,
- 10, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 2, 2,
- 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 7, 7, 12, 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12,
- 10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21, 1, 21, 21,
- 21, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
- 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 10, 12, 12, 12,
- 12, 12, 12, 12, 12, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 21, 21, 21, 21, 7, 10, 10, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
- 10, 7, 7, 7, 7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 21, 7, 21, 21, 21,
- 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 12,
- 12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 12, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 12, 12, 7, 10, 10,
- 12, 10, 10, 10, 10, 2, 2, 10, 10, 2, 2, 10, 10, 10, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 7, 7, 7,
- 7, 7, 10, 10, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2,
- 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
- 10, 10, 12, 12, 12, 10, 12, 7, 7, 7, 7, 21, 21, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 21, 12, 7,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12,
- 12, 10, 12, 12, 7, 7, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10,
- 10, 10, 12, 12, 12, 12, 2, 2, 10, 10, 10, 10, 12, 12, 10, 12,
- 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 7, 7, 7, 7, 12, 12, 2, 2,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12,
- 12, 21, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 10, 10,
- 12, 12, 12, 12, 12, 12, 10, 12, 7, 21, 2, 2, 2, 2, 2, 2,
- 10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26,
- 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 2, 2, 2, 2,
- 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 2, 7, 7, 7, 7,
- 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 2, 12, 12, 10, 12, 7,
- 10, 7, 10, 12, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7,
- 7, 10, 10, 10, 12, 12, 12, 12, 2, 2, 12, 12, 10, 10, 10, 10,
- 12, 7, 21, 7, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7,
- 7, 7, 7, 12, 12, 12, 12, 12, 12, 10, 7, 12, 12, 12, 12, 21,
- 21, 21, 21, 21, 21, 21, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21, 7, 21, 21,
- 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 10, 12,
- 7, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 2, 10, 12, 12, 12, 12, 12, 12,
- 12, 10, 12, 12, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7,
- 7, 12, 12, 12, 12, 12, 12, 2, 2, 2, 12, 2, 12, 12, 2, 12,
- 12, 12, 12, 12, 12, 12, 7, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 2,
- 12, 12, 2, 10, 10, 12, 10, 12, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 12, 10, 10, 21, 21, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23,
- 23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2,
- 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26,
- 6, 6, 6, 6, 21, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 15, 15, 15, 15, 15,
- 15, 15, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 7, 7, 7,
- 15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 12,
- 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 12,
- 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 21, 6, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 6, 6, 6, 6, 2, 6, 6, 6, 6, 6, 6, 6, 2, 6, 6, 2,
- 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 26, 12, 12, 21,
- 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10,
- 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12,
- 12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26,
- 26, 26, 12, 12, 12, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5,
- 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 2, 9, 9,
- 2, 2, 9, 2, 2, 9, 9, 2, 2, 9, 9, 9, 9, 2, 9, 9,
- 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 2, 5, 2, 5, 5, 5,
- 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2, 2, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 2, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2,
- 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 9, 9, 9, 9, 9, 9,
- 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5,
- 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25,
- 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 5, 2, 2, 13, 13,
+ 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42,
+ 7, 7, 43, 7, 44, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 45, 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, 22, 22, 22, 22, 22, 22,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26,
- 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12,
- 12, 12, 2, 12, 12, 2, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 7, 26,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 23,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 7, 2,
- 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 5, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 6, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15,
- 23, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2,
- 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2, 7, 2, 2, 2, 2,
- 2, 2, 7, 2, 2, 2, 2, 7, 2, 7, 2, 7, 2, 7, 7, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 2, 7, 2, 7, 2, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7,
- 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7,
- 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7,
- 25, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2,
- 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 2, 2, 2, 26, 26, 26, 26, 26, 2, 2, 2,
- 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20,
- 21, 22, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 24, 25,
- 0, 26, 27, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 0, 0,
- 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 0, 0, 0, 0,
- 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0,
- 43, 44, 45, 46, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 50, 0, 0, 0,
- 0, 0, 0, 51, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 0, 57, 58, 59,
- 60, 61, 62, 63, 64, 65, 66, 0, 67, 68, 0, 69, 70, 71, 72, 0,
- 61, 0, 73, 74, 75, 76, 0, 0, 70, 0, 77, 78, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 79, 80, 0, 0, 0, 0, 0, 0, 0, 0, 81,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 83, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 86, 0, 80, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 1, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 14, 15, 16, 17, 18, 19, 20, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 21, 0, 0, 0, 0, 0, 22, 23, 24,
- 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27,
- 28, 29, 0, 0, 0, 0, 30, 0, 0, 0, 31, 32, 33, 34, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 13, 35, 36, 0, 0, 26, 37, 38, 39, 0, 0, 0, 0, 0, 40,
- 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 42, 43, 1,
- 44, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 50, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
- 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 52, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 56, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 58, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 60, 61, 0, 0, 0, 0,
- 0, 0, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 67, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68,
- 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 71,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 74, 75, 0, 0, 0, 0, 0, 0, 0, 0,
- 76, 0, 68, 77, 0, 0, 0, 0, 0, 0, 78, 79, 80, 81, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 70, 0, 0, 0,
- 0, 82, 83, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0,
- 85, 0, 84, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 87,
- 88, 89, 90, 91, 0, 0, 0, 0, 0, 0, 0, 0, 92, 93, 94, 1,
- 1, 1, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98,
- 99,100,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 74, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 74,105,106, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 91, 0,107, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0,
- 1, 1, 91, 0, 0, 0, 0, 0, 0,108, 0, 0, 0, 0,109, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0, 76, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111,112,113, 0, 0, 0,
- 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 49, 0, 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,115,116, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 26,117, 0,118, 0, 0, 0, 0, 0,119, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 120, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122,123, 75, 0,
- 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0, 0, 0,
- 0, 0, 76,102, 0, 0, 0, 0, 0, 0, 0,125, 0, 0, 0, 0,
- 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0,
- 0, 0,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,126, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0,129, 0, 49, 0, 0,
- 26,130,130, 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0, 0, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,132, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,133, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,134, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,135,110, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0,102, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,137, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,138, 0, 0, 0, 0, 0, 0, 0,139, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,140, 0, 0, 0, 0,141, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 142,143,144,145,146,147, 0, 0, 0,148, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,149, 0, 0, 0,
- 0, 0, 0, 0,139, 1, 1,150,151,117, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0,
- 0,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,152, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,153, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
- 230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,
- 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
- 220,220,220,220,220,220,220,220, 1, 1, 1, 1, 1,220,220,220,
- 220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230,
- 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230,
- 233,234,234,233,234,234,233,230,230,230,230,230, 0, 0, 0,230,
- 230,230,230,230, 0,220,230,230,230,230,220,230,230,230,222,220,
- 230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,
- 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
- 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
- 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,
- 230,220,220,230,230,230,230,230,220,230,230,220, 35, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230,
- 230, 0, 0,230,230,230,230,220,230, 0, 0,230,230, 0,220,230,
- 230,220, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,230,220,230,230,
- 220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,
- 220,230,220,230,220,230,230, 0, 0, 0, 0, 0,230,230,220,230,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0, 0,230,230, 0,230,
- 230,230,230,230,230,230,230,230, 0,230,230,230, 0,230,230,230,
- 230,230, 0, 0, 0,220,220,220, 0, 0, 0, 0,230,220,220,220,
- 230,230,230,230, 0, 0,230,230,230,230,230,220,220,220,220,220,
- 230,230,230,230,230,230, 0,220,230,230,220,230,230,220,230,230,
- 230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230,
- 230,230,230,230, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
- 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,230, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 9,
- 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,103,103, 9, 0,
- 0, 0, 0, 0,107,107,107,107, 0, 0, 0, 0,118,118, 9, 0,
- 0, 0, 0, 0,122,122,122,122, 0, 0, 0, 0,220,220, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,220, 0,216, 0, 0,
- 0, 0, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
- 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, 0, 0,
- 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0,
- 9, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
- 0,230, 0, 0, 0,228, 0, 0, 0, 0, 0, 0, 0,222,230,220,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,220, 0, 0, 0,
- 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
- 230, 0, 0,220,230,230,230,230,230,220,220,220,220,220,220,230,
- 230,220, 0,220,220,230,230,220,220,230,230,230,230,230,220,230,
- 230,230,230, 0, 0, 0, 0,230,220,230,230,230,230,230,230,230,
- 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 7, 0,230,230,230, 0, 1,220,220,220,220,220,230,230,
- 220,220,220,220,230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0,220, 0, 0, 0, 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,
- 0, 0, 0, 0,230,230,220,230,230,230,230,230,230,230,220,230,
- 230,234,214,220,202,230,230,230,230,230,230,230,230,230,230,230,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+ 69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+ 84, 85, 86, 87, 88, 89, 69, 69, 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, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
+ 91, 34, 34, 34, 34, 34, 34, 34, 34, 92, 34, 34, 93, 94, 95, 96,
+ 97, 98, 99,100,101,102,103,104, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,105,
+ 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+ 107,107, 34, 34,108,109,110,111, 34, 34,112,113,114,115,116,117,
+ 118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
+ 132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
+ 147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
+ 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+ 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+ 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+ 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+ 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+ 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+ 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+ 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+ 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+ 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+ 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+ 244, 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, 34, 34,245, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
+ 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
+ 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25,
+ 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+ 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+ 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+ 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+ 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+ 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+ 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+ 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+ 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10,
+ 44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+ 11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+ 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11,
+ 32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+ 48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52, 2, 2, 2,
+ 16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62,
+ 36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65, 8, 9, 66, 2, 67,
+ 43, 43, 43, 43, 43, 60, 68, 2, 69, 36, 36, 36, 36, 70, 43, 43,
+ 7, 7, 7, 7, 7, 2, 2, 36, 71, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36,
+ 7, 7, 7, 7, 7, 36, 77, 78, 2, 2, 2, 2, 2, 2, 2, 79,
+ 70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36,
+ 36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44,
+ 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43,
+ 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43,
+ 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64,
+ 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44,
+ 36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 44, 43, 43, 43, 43,
+ 36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43,
+ 43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86,
+ 87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36,
+ 36, 43, 2, 7, 7, 7, 7, 7, 88, 36, 36, 36, 36, 36, 36, 36,
+ 70, 86, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 86,
+ 87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62,
+ 36, 43, 44, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 56, 63, 80,
+ 57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86,
+ 87, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61,
+ 44, 44, 44, 7, 7, 7, 7, 7, 43, 36, 70, 64, 44, 44, 44, 44,
+ 57, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
+ 61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44,
+ 61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
+ 57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87,
+ 87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 44, 44, 36, 62,
+ 78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36,
+ 61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36,
+ 36, 36, 36, 36, 36, 44, 44, 86, 85, 90, 44, 86, 90, 86, 87, 44,
+ 61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44,
+ 85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44,
+ 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
+ 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
+ 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
+ 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+ 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
+ 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
+ 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
+ 36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 89,
+ 86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44,
+ 62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96,
+ 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
+ 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
+ 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36,
+ 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67,
+ 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86,
+ 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
+ 57, 43, 43, 43, 43, 43, 43, 85, 43, 43, 60, 43, 36, 36, 70, 43,
+ 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67,
+ 67, 67, 67, 76, 67, 67, 92, 67, 2, 2, 97, 67, 21, 64, 44, 44,
+ 36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71,
+ 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 86, 43, 36, 36, 43,
+ 71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36,
+ 36, 85, 87, 85, 86, 86, 87, 94, 7, 7, 7, 7, 7, 86, 87, 67,
+ 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16,
+ 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44,
+ 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36,
+ 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43,
+ 2, 2, 2, 2, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44,
+ 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
+ 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
+ 102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44,
+ 36, 36, 36, 36, 36, 63, 2,105,106, 36, 36, 36, 61, 44, 44, 44,
+ 36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44,
+ 36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
+ 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86,
+ 86, 86, 86, 85, 87, 43, 43, 43, 43, 43, 2, 88, 2, 66, 70, 44,
+ 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
+ 2, 2, 2,108, 2, 59, 43, 84, 36, 83, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36,
+ 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 61, 43, 85, 86, 87, 85, 86, 44, 44,
+ 86, 85, 86, 86, 87, 43, 44, 44, 92, 44, 2, 7, 7, 7, 7, 7,
+ 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44,
+ 7, 7, 7, 7, 7,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 36, 36, 36, 70, 85, 87, 44, 2, 36, 36, 94, 85, 43, 43, 43, 80,
+ 85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57,
+ 2, 2, 2, 88, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,109,
+ 43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36,
+ 36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61, 44,
+ 97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21, 64,
+ 43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36,
+ 36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44, 2, 2,
+ 36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93, 2, 2,
+ 7, 7, 7, 7, 7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40, 2,
+ 16, 16, 16, 16,110, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+ 2, 2, 2, 2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43,
+ 85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 43, 61, 44, 44,
+ 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16,
+ 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,111, 40, 40,
+ 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11,
+ 16, 16, 16, 44, 11, 11, 11, 44, 16, 16, 16, 16, 48, 48, 48, 48,
+ 16, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, 16,112,112,112,112,
+ 16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41,
+ 16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41,
+ 44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65,
+ 120,120,120, 2,121,122,121,122, 2, 2, 2, 2,123, 65, 65,124,
+ 2, 2, 2, 2,125,126, 2,127,128, 2,129,130, 2, 2, 2, 2,
+ 2, 9,128, 2, 2, 2, 2,131, 65, 65,132, 65, 65, 65, 65, 65,
+ 133, 44, 27, 27, 27, 8,129,134, 27, 27, 27, 27, 27, 8,129,104,
+ 40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20,
+ 135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51,
+ 109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
+ 67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67,
+ 67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11,
+ 8, 8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27,
+ 105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44,
+ 8, 8,144, 67, 67, 8, 67, 67,144, 26, 67,144, 67, 67, 67,144,
+ 67, 67, 67, 67, 67, 67, 67, 8, 67,144,144, 67, 67, 67, 67, 67,
+ 67, 67, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 67, 67, 67, 67, 4, 4, 67, 67, 8, 67, 67, 67,145,146, 67, 67,
+ 67, 67, 67, 67, 67, 67,144, 67, 67, 67, 67, 67, 67, 26, 8, 8,
+ 8, 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8,
+ 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 92, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67,
+ 67, 67, 67, 67, 67, 27, 27, 27, 67, 67, 67, 26, 67, 67, 67, 67,
+ 26, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, 8, 8,
+ 67, 67, 67, 67, 67, 67, 67, 26, 67, 67, 67, 67, 4, 4, 4, 4,
+ 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67,
+ 8, 8,129,147, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4,
+ 8,129,148,148,148,148,148,148,148,148,148,148,147, 8, 8, 8,
+ 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8,
+ 8, 8,144, 26, 8, 8,144, 67, 67, 67, 44, 67, 67, 67, 67, 67,
+ 67, 67, 67, 55, 67, 67, 67, 67, 32, 11, 32, 34, 34, 34, 34, 11,
+ 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,140, 67, 67,138, 34,149,
+ 43, 32, 44, 44, 93, 2, 99, 2, 16, 16, 16,150, 44, 44,150, 44,
+ 36, 36, 36, 36, 44, 44, 44, 52, 64, 44, 44, 44, 44, 44, 44, 57,
+ 36, 36, 36, 61, 44, 44, 44, 44, 36, 36, 36, 61, 36, 36, 36, 61,
+ 2,121,121, 2,125,126,121, 2, 2, 2, 2, 6, 2,108,121, 2,
+ 121, 4, 4, 4, 4, 2, 2, 88, 2, 2, 2, 2, 2,120, 2, 2,
+ 108,151, 2, 2, 2, 2, 2, 2, 67, 2,152,148,148,148,153, 44,
+ 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+ 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157,
+ 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
+ 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69,
+ 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
+ 67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
+ 36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164, 2,
+ 7, 7, 7, 7, 7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70,
+ 51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43,
+ 36, 36, 36,105,105,105,105,105, 43, 2, 2, 2, 44, 44, 44, 44,
+ 41, 41, 41,162, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32,
+ 16, 32, 32, 32, 32, 32, 32, 32, 45, 16, 16, 16, 34, 34, 34, 32,
+ 32, 32, 32, 32, 42,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32,
+ 32, 32, 11, 11, 34,110, 44, 44, 32,150,150, 32, 32, 44, 44, 44,
+ 44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
+ 36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44,
+ 36, 36, 2, 2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 43, 44, 44, 44, 44, 2,
+ 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2,
+ 36, 36, 36, 70, 43, 43, 43, 43, 43, 86, 44, 44, 44, 44, 44, 93,
+ 36, 70, 86, 43, 43, 86, 43, 86,107, 2, 2, 2, 2, 2, 2, 52,
+ 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36,
+ 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 85,
+ 87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44,
+ 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 94, 85, 36,
+ 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 62, 83, 2, 36, 36, 36, 36, 36, 94, 43, 86,
+ 2, 83,169, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61,
+ 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,114, 40, 40,
+ 16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44,
+ 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
+ 170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,
+ 16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71,
+ 36, 36, 36, 36,172, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+ 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+ 41,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67,
+ 2, 2, 2,152,130, 44, 44, 44, 6,173,174,148,148,148,148,148,
+ 148,148,130,152,130, 2,127,175, 2, 64, 2, 2,156,148,148,130,
+ 2,176, 8,177, 66, 2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 61, 79, 93, 2, 3, 2, 4, 5, 6, 2,
+ 16, 16, 16, 16, 16, 17, 18,129,130, 4, 2, 36, 36, 36, 36, 36,
+ 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+ 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44,
+ 20,178, 56,135, 26, 8,144, 92, 44, 44, 44, 44, 79, 65, 67, 44,
+ 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62,
+ 2, 64, 44,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
+ 105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92,
+ 67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
+ 155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36,
+ 182,105,105, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16,
+ 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44,
+ 36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93,
+ 11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16,
+ 16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44,
+ 40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44,
+ 36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
+ 36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27,
+ 44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27,
+ 36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93,
+ 36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27,
+ 70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36,
+ 36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27,100, 44, 44, 44,
+ 2, 2, 2, 2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30,
+ 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36,
+ 36, 36, 70, 80, 44,179, 27, 27, 2, 2, 2, 64, 44, 44, 44, 44,
+ 36, 36, 36, 44, 93, 2, 2, 2, 36, 36, 36, 44, 27, 27, 27, 27,
+ 36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93, 2, 64, 44,
+ 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
+ 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
+ 27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
+ 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+ 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44,
+ 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+ 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+ 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7,
+ 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2,
+ 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7,
+ 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44,
+ 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87,
+ 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+ 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
+ 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
+ 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
+ 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
+ 61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44,
+ 61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44,
+ 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 94, 86, 43, 43, 43, 43,
+ 86, 43, 85, 71, 36, 63, 2, 2, 7, 7, 7, 7, 7, 2, 93, 71,
+ 86, 87, 43, 43, 85, 85, 86, 87, 85, 43, 36, 72, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 94, 86, 43, 43, 44, 86, 86, 43, 87,
+ 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 43, 44,
+ 86, 87, 43, 43, 43, 85, 87, 87, 60, 2, 61, 44, 44, 44, 44, 44,
+ 2, 2, 2, 2, 2, 2, 64, 44, 36, 36, 36, 36, 36, 70, 87, 86,
+ 43, 43, 43, 87, 63, 44, 44, 44, 86, 43, 43, 87, 43, 43, 44, 44,
+ 7, 7, 7, 7, 7, 27, 2, 97, 43, 43, 43, 43, 87, 60, 44, 44,
+ 27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
+ 36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71,
+ 98, 87, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
+ 94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44,
+ 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
+ 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
+ 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2,
+ 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44,
+ 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44,
+ 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+ 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+ 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+ 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+ 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2,
+ 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
+ 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
+ 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+ 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+ 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
+ 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44,
+ 36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
+ 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
+ 86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
+ 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+ 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
+ 43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
+ 67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
+ 86,187, 65, 65, 65, 84, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67,
+ 67, 67, 67, 67, 67, 43, 43, 67, 67, 43, 76, 44, 44, 44, 44, 44,
+ 27, 27, 44, 44, 44, 44, 44, 44, 11, 11, 11, 11, 11, 16, 16, 16,
+ 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
+ 16, 16,110, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 47, 11, 44, 47, 48, 47, 48, 11, 47, 11,
+ 11, 11, 11, 16, 16,150,150, 16, 16, 16,150, 16, 16, 16, 16, 16,
+ 16, 16, 11, 48, 11, 47, 48, 11, 11, 11, 47, 11, 11, 11, 47, 16,
+ 16, 16, 16, 16, 11, 48, 11, 47, 11, 11, 47, 47, 44, 11, 11, 11,
+ 47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
+ 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 44, 11, 11, 11, 11,
+ 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16,
+ 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16,
+ 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16,
+ 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 44, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 43, 43, 43, 76, 67, 50, 43, 43,
+ 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
+ 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
+ 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
+ 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+ 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+ 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+ 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77,
+ 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+ 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
+ 36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
+ 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
+ 188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
+ 27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36,
+ 62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44,
+ 44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
+ 62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
+ 36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
+ 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
+ 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
+ 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
+ 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
+ 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
+ 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
+ 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
+ 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
+ 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
+ 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
+ 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
+ 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
+ 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
+ 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
+ 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
+ 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
+ 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
+ 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
+ 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
+ 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
+ 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
+ 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
+ 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
+ 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
+ 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
+ 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
+ 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
+ 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
+ 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
+ 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
+ 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
+ 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
+ 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
+ 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
+ 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
+ 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
+ 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
+ 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
+ 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
+ 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
+ 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
+ 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
+ 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
+ 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
+ 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
+ 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
+ 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
+ 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
+ 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
+ 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
+ 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
+ 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
+ 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
+ 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
+ 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
+ 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
+ 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
+ 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
+ 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
+ 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
+ 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
+ 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
+ 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
+ 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
+ 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
+ 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
+ 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
+ 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
+ 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
+ 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
+ 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
+ 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
+ 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
+ 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
+ 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
+ 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
+ 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
+ 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
+ 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
+ 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
+ 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
+ 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
+ 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
+ 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
+ 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
+ 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
+ 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
+ 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
+ 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
+ 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
+ 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
+ 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
+ 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
+ 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
+ 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
+ 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
+ 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
+ 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
+ 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
+ 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
+ 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
+ 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
+ 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
+ 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
+ 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
+ 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
+ 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
+ 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
+ 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
+ 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
+ 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
+ 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
+ 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
+ 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
+ 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
+ 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
+ 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
+ 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
+ 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
+ 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
+ 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
+ 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
+ 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
+ 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
+ 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
+ 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
+ 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
+ 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
+ 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
+ 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
- 230,230,230,230, 1, 1, 1,230,230, 0, 0, 0, 0,230, 0, 0,
- 0, 1, 1,230,220,230, 1, 1,220,220,220,220,230, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0,218,228,
- 232,222,224,224, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 230,230,230,230,230,230,230,230,230,230, 0, 0, 0, 0, 0, 0,
- 0, 0, 9, 0, 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 9,
- 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,230, 0,230,230,
- 220, 0, 0,230,230, 0, 0, 0, 0, 0,230,230, 0,230, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0,230,230,230,230,
- 230,230,230,220,220,220,220,220,220,220,230,230,230,230,230, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,230,230, 1,220, 0,
- 0, 0, 0, 9, 0, 0, 0, 0, 0,230,220, 0, 0, 0, 0,230,
- 230, 0, 0, 0, 0, 0, 0, 0, 0, 0,220,220,230,230,230,220,
- 230,220,220,220, 0, 0,230,220,230,220, 0, 0, 0, 9, 7, 0,
- 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7,
- 7, 0, 0, 0,230,230,230,230,230, 0, 0, 0, 0, 0, 9, 0,
- 0, 0, 7, 0, 0, 0, 9, 7, 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0,
- 0, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
- 9, 9, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,230,230,230,230,
- 230,230,230, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 0, 0, 0, 0, 0, 0,216,216, 1, 1, 1, 0, 0,
- 0,226,216,216,216,216,216, 0, 0, 0, 0, 0, 0, 0, 0,220,
- 220,220,220,220,220,220,220, 0, 0,230,230,230,230,230,220,220,
- 0, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 0,230,230,
- 230, 0, 0, 0,230, 0, 0,230,230,230,230,230,230,230, 0,230,
- 230, 0,230,230,220,220,220,220,220,220,220, 0,230,230, 7, 0,
- 0, 0, 0, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
- 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
+ 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
+ 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
+ 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
+ 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
+ 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
+ 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17,
+ 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
+ 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17,237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 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, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 7, 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, 8, 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, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 10, 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,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2,
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8,
+ 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0,
+ 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0,
+ 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41,
+ 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0,
+ 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0,
+ 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10,
0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
28, 29, 30, 31, 0, 0, 20, 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, 20, 20,
- 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
- 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
- 0, 40, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21,
- 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
- 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4,
+ 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35,
+ 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8,
+ 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21,
+ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0,
0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 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, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 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, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 27, 27, 28, 29, 30, 31, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 34, 34, 34, 34, 58, 59, 59, 60, 34,
- 34, 34, 34, 34, 34, 34, 61, 62, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 63, 64, 34, 65, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 70, 71, 72, 34, 34,
- 34, 34, 73, 34, 34, 34, 34, 34, 34, 34, 34, 74, 75, 76, 77, 78,
- 79, 80, 34, 81, 82, 83, 34, 84, 85, 34, 86, 87, 88, 89, 17, 90,
- 91, 92, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 93, 25, 25, 25, 25, 25, 25, 25, 94,
- 95, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 96, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 97, 34, 34, 34, 34, 34, 34,
- 25, 98, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 99, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 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, 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, 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, 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, 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, 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, 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, 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,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20,
+ 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
+ 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
+ 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
+ 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
+ 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
+ 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+ 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
+ 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
+ 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
+ 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
+ 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
+ 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
+ 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
+ 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
+ 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
+ 96, 96,178,179,180,181,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
+ 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
+ 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
+ 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
+ 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
+ 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
+ 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96,
+ 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1,
+ 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
- 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
- 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19,
+ 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
+ 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4,
4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 2, 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,
+ 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14,
+ 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 2, 2, 95, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37,
+ 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
+ 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7,
7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
+ 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
- 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2,
2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
- 2, 2, 11, 2, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2,
2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10,
+ 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10,
+ 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
- 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2,
2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
- 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
- 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
- 22, 22, 22, 22, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
+ 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2,
+ 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
+ 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2,
+ 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
+ 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
+ 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2,
23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
- 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2,
+ 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
- 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
- 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2,
- 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2,
+ 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16,
+ 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
+ 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 2, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 36, 36,
- 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
+ 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36,
+ 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2,
+ 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24,
+ 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 2, 2, 2, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18,
+ 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18,
+ 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
- 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
- 2, 2, 2, 8, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
- 30, 30, 30, 30, 30, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12,
+ 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
+ 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
+ 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30,
2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 29, 29,
- 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 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,
- 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 0, 0, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 2,
+ 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2,
2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 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, 48,
- 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2,
+ 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32,
+ 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32,
+ 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48,
+ 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52,
+ 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58,
58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91,
+ 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1,
1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 2, 76, 76,
76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2,
- 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2,
- 2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2,
- 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 2, 2, 8, 8, 8, 76, 76, 76, 76, 76, 76, 76, 76, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70,
+ 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70,
+ 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2,
+ 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 6, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9,
- 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9,
- 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
+ 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9,
+ 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9,
+ 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9,
+ 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19,
+ 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2,
2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
- 19, 19, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27,
27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55,
- 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2,
- 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 61, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 30, 30, 30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 1, 1, 1, 1, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13,
+ 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55,
+ 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
+ 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13,
13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0,
- 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0,
- 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
- 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2,
+ 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12,
+ 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39,
+ 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79,
+ 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0,
+ 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 19, 19,
+ 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2,
19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 2, 2,
- 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2,
- 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65,
+ 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75,
2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12,
12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 2, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33,
33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68,
2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 30,
- 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19,
- 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30,
+ 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, 87,
+ 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12,
+ 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13,
2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2,
- 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14,
- 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
- 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
- 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14,
+ 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1,
+ 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3,
+ 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
- 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
- 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 2, 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, 49, 2, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
+ 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0,
+ 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0,
0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2,
+ 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2,
2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118,
- 118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,
118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 2, 2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40,
+ 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50,
2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,
- 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,135,135,
- 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
- 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,106,106,
- 106,106,106,106,106,106,106,106,106,106,106,106,106,106, 2, 2,
- 2, 2, 2, 2, 2, 2,104,104,104,104,104,104,104,104,104,104,
+ 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104,
104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161,
161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161,
- 161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,161,
- 161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,161,
- 2,161,161, 2, 2, 2,110,110,110,110,110,110,110,110,110,110,
- 110,110,110,110,110,110,110,110,110,110,110,110,110, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,110,110,110,110,110,110, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,110,110,110,110,110,110,110,110, 2, 2,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 2, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
+ 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,110,110,
+ 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110,
+ 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2,
+ 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
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, 2, 47, 47, 2,
- 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81, 81, 81,
- 81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120,
+ 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120,
120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
- 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
- 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,116,116,
- 116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128,
+ 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,
128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
- 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
- 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
- 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
- 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2,
- 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 97, 97,
+ 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+ 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2,
97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2,
2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57,
- 57, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2,
- 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
- 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117,
+ 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2,
+ 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
- 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
- 2,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78,
78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78,
78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 83, 83,
- 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2, 82, 82,
- 82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,
- 122,122,122, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,122,
- 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
- 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
+ 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122,
+ 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122,
+ 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130,
- 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,130,130,130, 2, 2, 2, 2, 2, 2, 2,
- 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
- 144,144,144,144,144,144,144,144,144,144,144,144,144,144, 2, 2,
- 2, 2, 2, 2, 2, 2,144,144,144,144,144,144,144,144,144,144,
- 2, 2, 2, 2, 2, 2,156,156,156,156,156,156,156,156,156,156,
- 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
- 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,147,147,
- 147,147,147,147,147,147,147,147,147,147,147,147,147,147, 2, 2,
- 2, 2, 2, 2, 2, 2,148,148,148,148,148,148,148,148,148,148,
- 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
+ 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,
+ 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156,
+ 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,147,147,
+ 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158,
- 158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153,
- 153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149,
- 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
+ 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2,
2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101,101,
- 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, 2,
- 2, 2, 2, 2, 2, 2,101,101,101,101,101,101,101,101,101,101,
+ 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,
+ 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101,
2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 2,
- 2, 2, 2, 2, 2, 2,111,111,111,111,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,100,100,100,100,100,100,100,100,100,100,
- 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
+ 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111,
+ 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,
108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108,
- 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
- 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2,
- 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
+ 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2,
129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
- 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
- 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
- 109, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
+ 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,
+ 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109,
2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107,
107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
- 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
- 2, 1,107,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
+ 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2,
+ 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2,
2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,
2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107,
- 107,107,107, 2, 2, 2,107,107,107,107,107, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
- 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
- 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 124,124,124,124,124,124,124,124,124,124,124,124,124,124, 2, 2,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,123,123,
- 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
- 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,
- 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
- 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
- 126, 2, 2,126,126,126,126,126,126,126,126,126,126,126,126,126,
- 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,142,142,142,142,142,142,142,142,142,142,
- 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
- 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
+ 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
+ 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,
+ 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,
+ 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114,
+ 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114,
+ 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,
+ 102,102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,
+ 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126,
+ 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142,
+ 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125,
125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154,
2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154,
- 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2,
- 2,154,154,154,154,154,154,154,154,154,154,154,154, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154,154,154,154,
- 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
- 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
- 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,141,141,141,141,141,141,141,141,141,141,
- 141,141,141,141,141,141,141,141,141,141,141,141,141,141, 2, 2,
- 2, 2, 2, 2, 2, 2,140,140,140,140,140,140,140,140,140,140,
- 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121,121,
- 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, 2,
+ 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,
+ 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150,
+ 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140,
+ 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121,
+ 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7,
2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
- 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
- 133,133,133,133,133,133,133,133,133,133,133,133, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133,133,
- 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134,134,134,
- 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134,134,134,
- 134,134,134,134,134,134,134,134,134,134,134,134,134,134, 2,134,
- 134,134,134,134,134,134,134,134,134,134,134,134,134, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138, 2,138,138,
- 2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
- 138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, 2,
- 138, 2,138,138, 2,138,138,138,138,138,138,138,138,138, 2, 2,
- 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138,138,138,138,
+ 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134,
+ 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134,
+ 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138,
+ 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138,
+ 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138,
2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
- 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,143,143,143,143,
- 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145,145,
- 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, 2,
- 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145,
+ 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163,
+ 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163,
+ 163, 2, 2, 2,163,163,163,163, 2, 2, 2, 2, 2, 2, 86, 2,
+ 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157,
- 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 80, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2,
- 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127,
- 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2,
+ 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63,
+ 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157,
+ 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2,127,127,
+ 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2,
2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115,
- 115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
- 115,115,115,115,115, 2,115,115,115,115,115,115,115,115,115,115,
- 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159, 2,159,159,159,159,159,159,159,159,159,159,
+ 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
+ 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159,
2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103,
- 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
- 103,103,103,103, 2, 2,103,103,103,103,103,103, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119,
- 2,119,119,119,119,119,119,119, 2,119,119,119,119,119,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,
+ 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119,
+ 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2,
2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146,
- 146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2,
- 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136,136,
- 136,136,136,136,136,136,136,136,136,136,136,136,136,136, 2, 2,
- 2, 2, 2, 2, 2, 2,155,155,155,155,155,155,155,155,155,155,
- 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136, 2,
+ 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139,
+ 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155,
+ 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2,136, 2,
2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17,
- 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 2,
- 2, 2, 2, 2, 2, 2,139,139,139,139,139,139,139,139,139,139,
- 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
- 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
- 105, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 105,105,105, 2, 2, 2,105,105,105,105,105,105,105,105,105, 2,
- 2, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
+ 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15,
+ 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
+ 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,
+ 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,
+ 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105,
+ 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 9, 9, 9, 9, 9, 9, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2,
+ 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0,
2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 0, 0,131,131,131,131,131,131,131,131,131,131,
- 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
- 131,131, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2,131,131,131,131,131, 2,131,131,131,131,131,131,131,131,131,
- 131,131,131,131,131,131, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56,
- 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2,
- 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
- 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
- 151,151,151, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 151,151,151,151, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
- 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
- 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 2, 30, 30, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
- 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
- 113,113,113,113,113,113,113,113,113,113,113,113,113, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132,
- 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
- 132,132, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132,
- 2, 2, 2, 2,132,132, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3,
- 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3,
- 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0,
- 0, 0, 0, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2,
- 2, 2, 2, 2, 2, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0,
- 0, 0, 0, 7, 8, 9, 10, 11, 0, 12, 0, 0, 0, 0, 13, 0,
- 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 0, 17, 18, 19,
- 0, 0, 0, 20, 21, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 0,
- 0, 0, 0, 27, 28, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131,
+ 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,
+ 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56,
+ 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56,
+ 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6,
+ 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,
+ 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151,
+ 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,
+ 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152,
+ 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
+ 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2, 30, 30,
+ 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
+ 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132,
+ 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132,
+ 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3,
+ 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2,
+ 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3,
+ 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2,
+ 2, 0, 0, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
+ 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13,
+ 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 0, 0, 0, 41, 0, 42, 43, 44, 45,
- 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33,
+ 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44,
+ 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48,
0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 50, 51, 52, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 64, 0, 0, 0, 0, 0,
- 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0,
+ 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69,
+ 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0,
+ 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,
+ 110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,
+ 132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
+ 148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,
+ 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,
+ 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
+ 193,194,195,196,197,198,199,200,201,202,203,204,205,206, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 78, 79, 80, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[11584] =
+_hb_ucd_u16[9320] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -3160,11 +2209,9 @@ _hb_ucd_u16[11584] =
136, 48, 48, 137, 138, 139, 140, 140, 141, 48, 142, 143, 144, 145, 140, 140,
146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 140, 140,
48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 168, 169, 48, 48, 168, 48, 48, 170, 171, 172, 48, 48,
- 48, 171, 48, 48, 48, 173, 174, 175, 48, 176, 9, 9, 9, 9, 9, 177,
- 178, 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, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 168, 169, 48, 48,
+ 168, 48, 48, 170, 171, 172, 48, 48, 48, 171, 48, 48, 48, 173, 174, 175,
+ 48, 176, 9, 9, 9, 9, 9, 177, 178, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183,
48, 184, 48, 185, 48, 186, 187, 188, 48, 48, 48, 189, 190, 191, 192, 193,
194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199,
@@ -3177,49 +2224,30 @@ _hb_ucd_u16[11584] =
241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
- 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
- 280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209,
- 209, 209, 287, 140, 288, 140, 271, 271, 271, 289, 209, 209, 209, 209, 290, 271,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293,
- 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 279, 279, 279, 279, 279, 279, 279, 279, 280, 209, 281, 209, 209, 209, 209, 282,
+ 209, 283, 279, 284, 209, 285, 286, 209, 209, 209, 287, 140, 288, 140, 271, 271,
+ 271, 289, 209, 209, 209, 209, 290, 271, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 291, 292, 209, 209, 293, 209, 209, 209, 209, 209, 209, 294, 209,
209, 209, 209, 209, 209, 209, 295, 296, 271, 297, 209, 209, 298, 279, 299, 279,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 279, 279, 279, 279, 279, 279, 279, 279, 300, 301, 279, 279, 279, 302, 279, 303,
- 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
- 209, 209, 209, 279, 304, 209, 209, 305, 209, 306, 209, 209, 209, 209, 209, 209,
- 9, 9, 9, 11, 11, 11, 307, 308, 13, 13, 13, 13, 13, 13, 309, 310,
- 11, 11, 311, 48, 48, 48, 312, 313, 48, 314, 315, 315, 315, 315, 32, 32,
- 316, 317, 318, 319, 320, 321, 140, 140, 209, 322, 209, 209, 209, 209, 209, 323,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324, 140, 325,
+ 300, 301, 279, 279, 279, 302, 279, 303, 209, 209, 209, 279, 304, 209, 209, 305,
+ 209, 306, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 307, 308,
+ 13, 13, 13, 13, 13, 13, 309, 310, 11, 11, 311, 48, 48, 48, 312, 313,
+ 48, 314, 315, 315, 315, 315, 32, 32, 316, 317, 318, 319, 320, 321, 140, 140,
+ 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 325,
326, 327, 328, 329, 136, 48, 48, 48, 48, 330, 178, 48, 48, 48, 48, 331,
332, 48, 48, 136, 48, 48, 48, 48, 200, 333, 48, 48, 209, 209, 323, 48,
209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 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, 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, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209,
- 48, 338, 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, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 287, 48, 48, 229,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345,
- 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 356,
- 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364,
- 64, 48, 365, 48, 366, 367, 48, 151, 76, 48, 48, 368, 369, 370, 371, 372,
- 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382,
- 383, 384, 315, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192,
- 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, 48, 388, 48, 389, 48, 48, 206,
- 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
- 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 209, 209, 209, 209, 48, 338, 48, 48, 48, 48, 48, 48,
+ 151, 209, 209, 209, 287, 48, 48, 229, 339, 48, 340, 140, 13, 13, 341, 342,
+ 13, 343, 48, 48, 48, 48, 344, 345, 31, 346, 347, 348, 13, 13, 13, 349,
+ 350, 351, 352, 353, 354, 355, 140, 356, 357, 48, 358, 359, 48, 48, 48, 360,
+ 361, 48, 48, 362, 363, 192, 32, 364, 64, 48, 365, 48, 366, 367, 48, 151,
+ 76, 48, 48, 368, 369, 370, 371, 372, 48, 48, 373, 374, 375, 376, 48, 377,
+ 48, 48, 48, 378, 379, 380, 381, 382, 383, 384, 315, 11, 11, 385, 386, 11,
+ 11, 11, 11, 11, 48, 48, 387, 192, 48, 48, 388, 48, 389, 48, 48, 206,
+ 390, 390, 390, 390, 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 391,
48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 140, 140,
392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 400, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403,
32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410,
411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419,
@@ -3229,644 +2257,524 @@ _hb_ucd_u16[11584] =
48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140,
9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439,
48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 314, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140,
448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453,
48, 454, 48, 455, 140, 140, 140, 140, 48, 48, 48, 456, 271, 457, 271, 271,
458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467,
48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
- 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 271, 476, 48, 48, 477, 478, 140, 140, 140, 140,
- 48, 464, 479, 48, 62, 480, 140, 48, 481, 140, 140, 48, 482, 140, 48, 314,
- 483, 48, 48, 484, 485, 457, 486, 487, 222, 48, 48, 488, 489, 48, 196, 192,
- 490, 48, 491, 492, 493, 48, 48, 494, 222, 48, 48, 495, 496, 497, 498, 499,
- 48, 97, 500, 501, 140, 140, 140, 140, 502, 503, 504, 48, 48, 505, 506, 192,
- 507, 83, 84, 508, 509, 510, 511, 512, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 518, 519, 520, 521, 140, 140,
- 48, 48, 48, 522, 523, 192, 524, 140, 48, 48, 525, 526, 192, 140, 140, 140,
- 48, 173, 527, 528, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
- 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
- 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
- 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 557,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 100, 271, 558, 559, 560,
- 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, 207, 140, 140, 140, 140, 140, 140,
- 272, 272, 272, 272, 272, 272, 561, 562, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
- 48, 48, 200, 564, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
- 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
- 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, 48, 48, 48, 48, 48, 48, 440,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 140,
- 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324,
- 209, 209, 586, 209, 209, 209, 587, 588, 589, 209, 590, 209, 209, 209, 288, 140,
- 209, 209, 209, 209, 591, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 592,
- 209, 209, 209, 209, 209, 287, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140,
- 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
- 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
- 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
- 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 628, 629, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 630, 631, 632, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 151, 633, 634, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 638, 200,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 639, 585, 140, 140,
- 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 498, 271, 271, 641, 642, 140, 140, 140, 140,
- 498, 271, 643, 644, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
- 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
- 659, 209, 209, 325, 660, 661, 324, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 662,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 663, 426, 426,
- 209, 209, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 660, 325, 427,
- 325, 209, 209, 209, 664, 176, 209, 209, 664, 209, 657, 661, 140, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 323, 657, 665, 287, 209, 426, 288, 324, 176, 664, 287,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 666, 209, 209, 288, 140, 140, 192,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140,
- 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, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 196, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 204, 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, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 478, 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, 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, 48, 100, 140,
- 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 71, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 667, 140, 668, 668, 668, 668, 668, 668, 140, 140, 140, 140, 140, 140, 140, 140,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 669,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 670,
- 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0,
- 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 11, 11, 11, 13, 11,
- 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24,
- 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27,
- 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38,
- 39, 39, 40, 41, 42, 43, 44, 27, 45, 46, 27, 27, 27, 27, 47, 27,
- 48, 48, 48, 48, 48, 49, 50, 48, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 65, 66, 67, 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, 100, 101, 102, 103, 104, 105, 106,
- 107, 108, 109, 109, 110, 111, 112, 109, 113, 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 122, 123, 122, 124, 125, 125, 126, 127, 128, 129, 130, 131, 125, 125,
- 132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 125, 125,
- 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
- 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
- 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
- 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
- 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 8, 195, 125, 125, 125,
- 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
- 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
- 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 8,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 11, 217, 11, 11, 217, 218, 11, 219, 11, 11, 11, 220, 220, 221, 11, 222,
- 223, 0, 0, 0, 0, 0, 224, 225, 226, 227, 0, 0, 228, 8, 8, 229,
- 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 234, 125, 235, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 237, 0, 238, 0, 0, 0, 0, 0, 0,
- 239, 239, 239, 239, 239, 239, 4, 4, 240, 240, 240, 240, 240, 240, 240, 241,
- 139, 139, 140, 242, 242, 242, 243, 244, 143, 245, 246, 246, 246, 246, 14, 14,
- 0, 0, 0, 0, 0, 247, 125, 125, 248, 249, 248, 248, 248, 248, 248, 250,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 125, 252,
- 253, 0, 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 260, 260, 261,
- 262, 263, 263, 264, 142, 142, 142, 142, 265, 0, 263, 263, 0, 0, 266, 260,
- 142, 265, 0, 0, 0, 0, 142, 267, 0, 0, 0, 0, 0, 260, 260, 268,
- 260, 260, 260, 260, 260, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 0, 0, 0, 0,
- 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 270, 270, 270, 270, 271, 270, 270, 270, 272, 273, 273, 273,
- 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
- 274, 274, 275, 125, 14, 14, 14, 14, 14, 14, 276, 276, 276, 276, 276, 277,
- 0, 0, 278, 4, 4, 4, 4, 4, 279, 4, 4, 4, 280, 281, 125, 282,
- 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 48, 48,
- 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
- 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
- 309, 310, 246, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 315, 142, 316, 142, 142, 317,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
- 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 325, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 326, 27, 27, 27, 27, 27, 327, 27, 27, 328, 125, 125, 27,
- 8, 285, 329, 0, 0, 330, 331, 332, 27, 27, 27, 27, 27, 27, 27, 333,
- 334, 0, 1, 2, 1, 2, 335, 259, 260, 336, 142, 265, 337, 338, 339, 340,
- 341, 342, 343, 344, 345, 345, 125, 125, 342, 342, 342, 342, 342, 342, 342, 346,
- 347, 0, 0, 348, 11, 11, 11, 11, 349, 350, 351, 125, 125, 0, 0, 352,
- 125, 125, 125, 125, 125, 125, 125, 125, 353, 354, 355, 355, 355, 356, 357, 252,
- 358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
- 369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
- 377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
- 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 386, 385, 387, 388, 125, 389, 4, 4, 390, 125, 125, 125, 125,
- 391, 392, 392, 393, 394, 395, 396, 396, 397, 398, 399, 125, 125, 125, 400, 401,
- 402, 403, 404, 405, 125, 125, 125, 125, 406, 406, 407, 408, 407, 409, 407, 407,
- 410, 411, 412, 413, 414, 414, 415, 415, 416, 416, 125, 125, 417, 417, 418, 419,
- 420, 420, 420, 421, 422, 423, 424, 425, 426, 427, 428, 125, 125, 125, 125, 125,
- 429, 429, 429, 429, 430, 125, 125, 125, 431, 431, 431, 432, 431, 431, 431, 433,
- 434, 434, 435, 436, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 27, 45, 437, 437, 438, 439, 125, 125, 125, 125,
- 440, 440, 441, 442, 442, 443, 125, 444, 445, 125, 125, 446, 447, 125, 448, 449,
- 450, 450, 450, 450, 451, 452, 450, 453, 454, 454, 454, 454, 455, 456, 457, 458,
- 459, 459, 459, 460, 461, 462, 462, 463, 464, 464, 464, 464, 464, 464, 465, 466,
- 467, 468, 467, 469, 125, 125, 125, 125, 470, 471, 472, 473, 473, 473, 474, 475,
- 476, 477, 478, 479, 480, 481, 482, 483, 125, 125, 125, 125, 125, 125, 125, 125,
- 484, 484, 484, 484, 484, 485, 486, 125, 487, 487, 487, 487, 488, 489, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 490, 490, 490, 491, 490, 492, 125, 125,
- 493, 493, 493, 493, 494, 495, 496, 125, 497, 497, 497, 498, 498, 125, 125, 125,
- 499, 500, 501, 499, 502, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 503, 503, 503, 504, 125, 125, 125, 125, 125, 125, 505, 505, 505, 505, 505, 506,
- 507, 508, 509, 510, 511, 512, 125, 125, 125, 125, 513, 514, 514, 513, 515, 125,
- 516, 516, 516, 516, 517, 518, 518, 518, 518, 518, 519, 154, 520, 520, 520, 521,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 522, 523, 523, 524, 525, 523, 526, 527, 527, 528, 529, 530, 125, 125, 125, 125,
- 531, 532, 532, 533, 534, 535, 536, 537, 538, 539, 540, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 541, 542,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 543, 544, 544, 544, 545,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 547, 125, 125, 125, 125, 125, 125,
- 546, 546, 546, 546, 546, 546, 548, 549, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 550, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 551, 551, 551, 551, 551, 551, 552,
- 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
- 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
- 553, 553, 554, 555, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 556, 556, 557, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 558, 559, 560, 561, 562, 562, 562, 562, 563, 564, 565, 566, 567,
- 568, 568, 568, 568, 569, 570, 571, 572, 568, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 573, 573, 573, 573, 573, 574, 125, 125, 125, 125, 125, 125,
- 575, 575, 575, 575, 576, 575, 575, 575, 577, 575, 125, 125, 125, 125, 578, 579,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 581,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582,
- 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 583, 125, 125,
- 584, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 585,
- 586, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
- 257, 257, 587, 125, 125, 588, 589, 590, 590, 590, 590, 590, 590, 590, 590, 590,
- 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 592, 592, 592, 592, 592, 592, 593, 594, 595, 596, 266, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 8, 8, 597, 8, 598, 0, 0, 0, 0, 0, 0, 0, 266, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 599,
- 0, 0, 600, 0, 0, 0, 601, 602, 603, 0, 604, 0, 0, 0, 235, 125,
- 11, 11, 11, 11, 605, 125, 125, 125, 125, 125, 125, 125, 125, 125, 0, 266,
- 0, 0, 0, 0, 0, 234, 0, 606, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 224, 0, 0, 0, 607, 608, 609, 610, 0, 0, 0,
- 611, 612, 0, 613, 614, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 617, 0, 0, 0,
- 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 618, 618, 618, 618, 618, 618, 618, 619, 620, 621, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 4, 622, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 623, 624, 625, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 626, 626, 627, 628, 629, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 630, 631, 125, 632, 632, 632, 633,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 634, 635,
- 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 125, 125,
- 639, 639, 639, 639, 640, 641, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 334, 0, 0, 0, 642, 125, 125, 125, 125,
- 334, 0, 0, 247, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 643, 27, 644, 645, 646, 647, 648, 649, 650, 651, 652, 651, 125, 125, 125, 653,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 252, 0, 0, 0, 0, 0, 0, 266, 226, 334, 334, 334, 0, 599,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 125, 125, 125, 654, 0,
- 655, 0, 0, 252, 606, 656, 599, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 657, 350, 350,
- 0, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 606, 252, 228,
- 252, 0, 0, 0, 658, 285, 0, 0, 658, 0, 247, 656, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 266, 247, 659, 234, 0, 350, 235, 599, 285, 658, 234,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 235, 125, 125, 285,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 660, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 579, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 661, 125,
- 248, 318, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 662, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 663, 125, 0, 0, 0, 0, 0, 0, 125, 125, 125, 125, 125, 125, 125, 125,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
- 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
- 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
- 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
- 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
- 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
- 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
- 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
- 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
- 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
- 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
- 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
- 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
- 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
- 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
- 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
- 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
- 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
- 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
- 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 0,
- 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
- 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
- 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
- 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
- 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
- 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
- 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
- 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
- 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
- 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
- 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
- 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
- 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
- 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
- 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
- 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
- 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
- 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
- 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
- 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
- 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
- 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
- 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
- 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
- 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
- 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
- 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
- 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
- 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
- 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
- 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
- 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
- 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
- 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
- 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
- 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
- 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
- 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
- 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
- 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
- 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
- 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
- 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
- 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
- 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
- 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
- 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
- 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
- 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
- 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
- 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
- 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
- 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
- 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
- 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
- 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
- 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
- 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
- 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
- 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
- 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
- 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
- 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
- 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
- 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
- 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
- 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
- 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
- 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
- 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
- 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
- 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
- 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
- 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
- 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
- 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
- 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
- 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
- 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
- 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
- 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
- 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
- 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
- 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
+ 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48,
+ 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488,
+ 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495,
+ 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140,
+ 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514,
+ 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140,
+ 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140,
+ 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140,
+ 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532,
+ 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140,
+ 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196,
+ 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550,
+ 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48,
+ 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560,
+ 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+ 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+ 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569,
+ 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
+ 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573,
+ 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
+ 48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140,
+ 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+ 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206,
+ 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+ 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+ 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+ 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+ 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+ 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11,
+ 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11,
+ 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623,
+ 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632,
+ 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140,
+ 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140,
+ 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140,
+ 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192,
+ 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140,
+ 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+ 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+ 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+ 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
+ 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
+ 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
+ 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
+ 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
+ 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
+ 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
+ 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
+ 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
+ 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4,
+ 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
+ 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14,
+ 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21,
+ 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25,
+ 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31,
+ 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37,
+ 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26,
+ 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46,
+ 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62,
+ 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74,
+ 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86,
+ 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98,
+ 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109,
+ 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
+ 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
+ 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131,
+ 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
+ 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148,
+ 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154,
+ 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158,
+ 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
+ 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164,
+ 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
+ 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
+ 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
+ 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
+ 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
+ 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26,
+ 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194,
+ 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198,
+ 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178,
+ 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205,
+ 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210,
+ 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216,
+ 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9,
+ 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225,
+ 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230,
+ 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234,
+ 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2,
+ 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246,
+ 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14,
+ 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14,
+ 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0,
+ 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0,
+ 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26,
+ 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
+ 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
+ 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172,
+ 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285,
+ 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
+ 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294,
+ 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0,
+ 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
+ 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277,
+ 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299,
+ 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
+ 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
+ 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2,
+ 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314,
+ 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316,
+ 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322,
+ 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26,
+ 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
+ 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2,
+ 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
+ 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169,
+ 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352,
+ 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31,
+ 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0,
+ 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3,
+ 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296,
+ 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372,
+ 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369,
+ 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26,
+ 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382,
+ 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388,
+ 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394,
+ 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397,
+ 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402,
+ 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405,
+ 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412,
+ 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413,
+ 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26,
+ 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308,
+ 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422,
+ 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26,
+ 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435,
+ 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438,
+ 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446,
+ 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26,
+ 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455,
+ 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464,
+ 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26,
+ 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26,
+ 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476,
+ 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480,
+ 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484,
+ 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488,
+ 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494,
+ 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498,
+ 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501,
+ 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509,
+ 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518,
+ 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524,
+ 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527,
+ 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529,
+ 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531,
+ 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536,
+ 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537,
+ 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543,
+ 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551,
+ 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553,
+ 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178,
+ 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562,
+ 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574,
+ 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587,
+ 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26,
+ 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592,
+ 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597,
+ 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601,
+ 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601,
+ 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305,
+ 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603,
+ 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608,
+ 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612,
+ 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618,
+ 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26,
+ 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622,
+ 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
+ 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26,
+ 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635,
+ 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9,
+ 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0,
+ 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0,
+ 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14,
+ 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649,
+ 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652,
+ 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656,
+ 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18,
+ 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669,
+ 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26,
+ 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678,
+ 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678,
+ 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681,
+ 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276,
+ 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688,
+ 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694,
+ 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0,
+ 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26,
+ 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281,
+ 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0,
+ 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269,
+ 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0,
+ 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
+ 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
+ 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
+ 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
+ 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
+ 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
+ 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
+ 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
+ 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
+ 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
+ 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
+ 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
+ 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
+ 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
+ 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
+ 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
+ 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
+ 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
+ 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 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, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
+ 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
+ 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
+ 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
+ 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
+ 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
+ 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
- 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
- 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
- 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
- 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
- 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
- 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
- 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
- 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
- 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
- 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
- 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
- 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
- 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
- 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
- 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
- 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
- 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
- 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
- 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
- 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
- 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
- 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
- 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
- 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
- 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
- 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
- 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
- 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
- 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
- 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
- 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
- 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
- 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
- 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
+ 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
+ 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
+ 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
+ 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
+ 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
+ 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
+ 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
+ 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
+ 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
+ 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
+ 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
+ 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
+ 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
+ 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
+ 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
+ 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
+ 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
+ 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
+ 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
+ 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
+ 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
+ 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
+ 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
+ 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
+ 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
+ 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
+ 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
+ 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
+ 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
+ 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
+ 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
+ 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
+ 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
+ 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
+ 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
+ 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
+ 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
+ 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
+ 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
+ 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
+ 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
+ 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
+ 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
+ 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
+ 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
+ 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
+ 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
+ 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
+ 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
+ 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
+ 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
+ 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
+ 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
+ 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
+ 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
+ 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
+ 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
+ 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
+ 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
+ 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
+ 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
+ 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
+ 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
+ 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
+ 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
+ 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
+ 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
+ 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
+ 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
+ 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
+ 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
+ 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
+ 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
+ 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
+ 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
+ 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
+ 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
+ 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
+ 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
+ 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
+ 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
+ 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
+ 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
+ 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
+ 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
+ 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
+ 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
+ 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
+ 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
+ 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
+ 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
+ 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
+ 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
+ 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
+ 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
+ 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
+ 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
+ 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
+ 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
+ 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
+ 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
+ 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
+ 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
+ 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
+ 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
+ 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
+ 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
+ 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
+ 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
+ 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
+ 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
+ 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
+ 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
+ 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
+ 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
+ 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
+ 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
_hb_ucd_i16[196] =
@@ -3889,12 +2797,12 @@ _hb_ucd_i16[196] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2;
+ return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[15332+(((_hb_ucd_u8[13892+(((_hb_ucd_u8[12912+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0;
+ return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -3904,24 +2812,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16692+(((_hb_ucd_b4(16564+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[19446+(((_hb_ucd_u16[3168+(((_hb_ucd_u8[17652+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
+ return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[6400+(((_hb_ucd_u8[30070+(u>>6)])<<6)+((u)&63u))]:0;
+ return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#elif !defined(HB_NO_UCD_UNASSIGNED)
static const uint8_t
-_hb_ucd_u8[17936] =
+_hb_ucd_u8[14744] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -3929,7 +2837,7 @@ _hb_ucd_u8[17936] =
25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42,
- 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 7, 7, 43, 7, 44, 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, 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, 22, 22, 22, 22, 22, 22, 22, 22, 22,
@@ -3951,12 +2859,12 @@ _hb_ucd_u8[17936] =
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, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 45, 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, 22, 22, 22, 22, 22, 22,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
@@ -3975,35 +2883,36 @@ _hb_ucd_u8[17936] =
118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
- 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171,
- 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175,
- 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122,
+ 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+ 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+ 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122,
- 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186,
- 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189,
- 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195,
- 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209,
- 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122,
- 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216,
- 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122,
- 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232,
- 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34,
- 240, 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, 34, 34,241, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122,
- 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249,
+ 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+ 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+ 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+ 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+ 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+ 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+ 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+ 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+ 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+ 244, 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, 34, 34,245, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
+ 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -4066,7 +2975,7 @@ _hb_ucd_u8[17936] =
44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
- 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+ 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
@@ -4076,7 +2985,7 @@ _hb_ucd_u8[17936] =
36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44,
44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
- 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36,
+ 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36,
77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67,
7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86,
36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
@@ -4243,18 +3152,19 @@ _hb_ucd_u8[17936] =
44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
- 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44,
- 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44,
- 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44,
- 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57,
- 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44,
- 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43,
- 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44,
- 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85,
- 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2,
- 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44,
- 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80,
+ 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+ 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44,
+ 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+ 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+ 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7,
+ 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2,
+ 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7,
+ 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44,
+ 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87,
+ 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+ 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
@@ -4276,17 +3186,20 @@ _hb_ucd_u8[17936] =
70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2,
- 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
- 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36,
- 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43,
- 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
- 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
- 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90,
- 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
+ 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44,
+ 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44,
+ 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+ 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+ 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+ 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+ 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2,
27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+ 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44,
@@ -4294,7 +3207,8 @@ _hb_ucd_u8[17936] =
86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
- 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+ 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+ 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
@@ -4319,10 +3233,12 @@ _hb_ucd_u8[17936] =
43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
- 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
- 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
- 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80,
- 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96,
+ 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+ 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+ 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+ 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77,
+ 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+ 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
@@ -4335,156 +3251,136 @@ _hb_ucd_u8[17936] =
27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67,
- 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44,
+ 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
+ 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
- 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44,
- 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
- 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
- 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
- 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
- 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
- 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
- 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
- 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
- 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
- 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
- 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
- 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
- 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
- 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
- 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
- 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
- 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
- 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
- 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
- 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
- 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
- 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
- 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
- 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
- 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
- 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
- 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0,
- 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0,
- 0, 0, 0, 0, 6, 7, 8, 0, 9, 0, 10, 11, 0, 0, 12, 13,
- 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 0, 21, 0, 22, 23,
- 0, 24, 25, 0, 0, 24, 26, 27, 0, 24, 26, 0, 0, 24, 26, 0,
- 0, 24, 26, 0, 0, 0, 26, 0, 0, 24, 28, 0, 0, 24, 26, 0,
- 0, 29, 26, 0, 0, 0, 30, 0, 0, 31, 32, 0, 0, 33, 34, 0,
- 35, 36, 0, 37, 38, 0, 39, 0, 0, 40, 0, 0, 41, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 43, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0,
- 0, 47, 0, 0, 0, 0, 0, 0, 48, 0, 0, 49, 0, 50, 51, 0,
- 0, 52, 53, 54, 0, 55, 0, 56, 0, 57, 0, 0, 0, 0, 58, 59,
- 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 62, 63,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,
- 0, 0, 0, 65, 0, 0, 0, 66, 0, 67, 0, 0, 68, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 71,
- 0, 0, 0, 0, 0, 0, 0, 0, 72, 73, 0, 0, 0, 0, 53, 74,
- 0, 75, 76, 0, 0, 77, 78, 0, 0, 0, 0, 0, 0, 79, 80, 81,
- 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 82, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 85,
- 0, 0, 0, 86, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 89,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0,
- 0, 0, 92, 0, 93, 0, 0, 0, 0, 0, 72, 94, 0, 95, 0, 0,
- 96, 97, 0, 77, 0, 0, 98, 0, 0, 99, 0, 0, 0, 0, 0,100,
- 0,101, 26,102, 0, 0, 0, 0, 0, 0,103, 0, 0, 0,104, 0,
- 0, 0, 0, 0, 0, 65,105, 0, 0, 65, 0, 0, 0,106, 0, 0,
- 0,107, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0,
- 0,108,109, 0, 0, 0, 0, 78, 0, 44,110, 0,111, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0,
- 0, 0,112, 0,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,114,
- 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0,117, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,118,119,120, 0, 0, 0, 0,121, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,122,123, 0, 0, 0, 0, 0, 0,
- 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0,125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0,
- 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
+ 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
+ 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
+ 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
+ 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
+ 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
+ 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
+ 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
+ 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
+ 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
+ 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
+ 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
+ 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
+ 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
+ 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
+ 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
+ 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
+ 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
+ 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
+ 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
+ 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
+ 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
+ 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
+ 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
+ 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
+ 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
+ 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
+ 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
+ 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
+ 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
+ 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
+ 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
+ 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
+ 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
+ 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
+ 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
+ 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
+ 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
+ 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
+ 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
+ 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
+ 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
+ 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
+ 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
+ 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
+ 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
+ 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
+ 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
+ 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
+ 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
+ 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
+ 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
+ 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
+ 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
+ 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
+ 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
+ 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
+ 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
+ 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
+ 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
+ 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
+ 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
+ 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
+ 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
+ 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
+ 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
+ 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
+ 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
+ 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
+ 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
- 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 0, 0, 0, 0,
- 19, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 1,
- 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36,
- 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 1, 39,
- 14, 39, 40, 41, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,
- 0, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 0, 0,
- 0, 0, 19, 1, 21, 0, 0, 47, 0, 0, 0, 0, 0, 38, 48, 1,
- 1, 49, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0,
- 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1,
- 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 55,
- 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 56, 0, 60, 0, 0,
- 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 70, 0,
- 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 0, 0, 0,
- 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0,
- 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49,
- 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0,
- 0, 0, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 19, 84, 0,
- 62, 0, 0, 0, 0, 49, 1, 85, 0, 0, 0, 0, 1, 52, 15, 86,
- 36, 10, 21, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0,
- 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0,
- 0, 0, 88, 0, 0, 0, 0, 0, 0, 89, 0, 0, 88, 0, 0, 0,
- 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 87, 9, 12, 4,
+ 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
+ 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
+ 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
+ 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
+ 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
+ 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
+ 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
+ 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
+ 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
+ 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
+ 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
+ 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
+ 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
+ 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
+ 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
+ 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
- 1, 1, 1, 1, 1, 94, 95, 96, 0, 0, 0, 0, 97, 1, 98, 58,
- 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 61, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0,
- 0, 0, 0, 19, 0, 1, 1, 50, 0, 0, 0, 0, 0, 0, 0, 38,
- 0, 0, 0, 0, 50, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 62, 0, 0, 0, 0, 1, 1, 1, 1, 50, 0, 0, 0,
- 0, 0,104, 68, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0,
- 0, 0, 0, 0, 78, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,
- 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47,
- 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 87, 0,
- 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,109, 61,
- 0,110, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 19, 58, 0, 0, 0, 0, 0,111, 14, 52, 84, 0, 0, 0,
- 112, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 61,
- 0, 0, 0, 0, 0, 0,113, 0, 87, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
- 63, 89, 0, 0, 0, 0, 0, 59,115, 0, 0, 0, 0, 0, 0, 0,
- 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, 0,
- 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79,
- 78, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 8, 91, 0, 0,
- 0, 0, 0, 0, 1, 87, 0, 0, 0, 0, 0, 0,116, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
- 122, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0,
- 38, 58, 0, 0, 0, 0, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1,
- 48,105, 87, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4,122, 0, 0,
- 0, 1,123, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
+ 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
+ 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
+ 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
+ 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
+ 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
+ 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
+ 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
+ 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
+ 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
+ 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
+ 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
+ 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
+ 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
+ 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
+ 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
+ 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
+ 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
@@ -4515,51 +3411,54 @@ _hb_ucd_u8[17936] =
0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
- 220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33,
- 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27,
- 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 33,
+ 17, 49, 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26,
- 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33,
- 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0,
- 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9,
- 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0,
- 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1,
- 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20,
- 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0,
- 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31,
- 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,
- 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33,
- 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0,
- 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0,
- 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1,
- 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42,
- 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46,
- 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0,
- 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24,
- 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3,
+ 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3,
+ 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21,
+ 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3,
+ 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0,
+ 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0,
+ 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0,
+ 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19,
+ 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
+ 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39,
+ 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0,
+ 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47,
+ 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0,
+ 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57,
+ 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59,
+ 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60,
+ 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3,
+ 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0,
+ 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0,
+ 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0,
+ 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0,
+ 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0,
+ 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20,
+ 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9,
+ 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21,
+ 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21,
+ 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9,
+ 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45,
+ 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1,
+ 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+ 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42,
- 7, 7, 43, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
+ 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -4580,411 +3479,221 @@ _hb_ucd_u8[17936] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 44, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38,
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2,
- 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59,
- 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
+ 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
+ 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+ 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70,
- 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84,
- 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,102,103,104,105,
- 106,107,108,109,110,111, 96,112,113,114,115,116,117,118,119,119,
- 120,121,122,123,124,125,126,127,128,129,130,131,132, 96,133,134,
- 135,136,137,138,139,140,141,142,143, 96,144,145, 96,146,147,148,
- 149, 96,150,151,152,153,154,155, 96, 96,156,157,158,159, 96,160,
- 96,161,162,162,162,162,162,162,162,163,164,162,165, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,166,167,167,167,167,167,167,167,167,168, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96,
- 96, 96,171,171,171,171,172,173,174,175, 96, 96, 96, 96,176,177,
- 178,179,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
- 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
- 180,181,180,180,180,180,180,180,182,182,182,183,184, 96, 96, 96,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,185,186,187,188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 193,194, 59,195,196,197,198,199,200, 96,201,202,203, 59, 59,204,
- 59,205,206,206,206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,
- 208, 96,209, 96,210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96,
- 96,212,213,214,215, 96, 96, 96, 96, 96,216,217,218, 96,219,220,
- 96, 96,221,222, 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,
- 226,227,228,229, 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233,
+ 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+ 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+ 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+ 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
+ 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
+ 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
+ 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+ 182,182,182,182,182,182,182,182,182,182,182,182,182,183,182,182,
+ 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
+ 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
+ 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
+ 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
+ 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
+ 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
+ 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
+ 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 234, 70,235, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236,
- 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 70, 70, 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96,
- 96, 96,240, 96,241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3,
- 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0,
- 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19,
- 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0,
- 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9,
- 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9,
- 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1,
- 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4,
- 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2,
- 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0,
- 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37,
- 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2,
- 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64,
- 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2,
- 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2,
- 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0,
- 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2,
- 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5,
- 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5,
- 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2,
- 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11,
- 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11,
- 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2,
- 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10,
- 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2,
- 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10,
- 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21,
- 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21,
- 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21,
- 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22,
- 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22,
- 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2,
- 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2,
- 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2,
- 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23,
- 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23,
- 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23,
- 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2,
- 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16,
- 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16,
- 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2,
- 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20,
- 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2,
- 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36,
- 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36,
- 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2,
- 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2,
- 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2,
- 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18,
- 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2,
- 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25,
- 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2,
- 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0,
- 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33,
- 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8,
- 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30,
- 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28,
- 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2,
- 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0,
- 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0,
- 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2,
- 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2,
- 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2,
- 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2,
- 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28,
- 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48,
- 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2,
- 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2,
- 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91,
- 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62,
- 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93,
- 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70,
- 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73,
- 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8,
- 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19,
- 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9,
- 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19,
- 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9,
- 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2,
- 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0,
- 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2,
- 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
- 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2,
- 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56,
- 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55,
- 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2,
- 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
- 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13,
- 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13,
- 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1,
- 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96,
+ 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
+ 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0,
+ 19, 0, 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9,
+ 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
+ 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
+ 2, 9, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1,
+ 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 14, 14, 2,
+ 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3, 37, 37,
+ 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
+ 38, 38, 38, 38, 2, 2, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64,
+ 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 2, 95, 95,
+ 95, 95, 2, 2, 95, 2, 3, 3, 3, 2, 3, 3, 2, 2, 3, 3,
+ 0, 3, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0,
+ 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5,
+ 5, 2, 2, 2, 2, 5, 5, 5, 2, 5, 2, 11, 11, 11, 11, 11,
+ 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 2, 11, 2, 2, 11, 2,
+ 11, 2, 2, 2, 11, 11, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 2, 10, 10, 2, 10, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2,
+ 10, 10, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 21, 21, 21, 21, 2, 2, 21, 21, 2, 21, 2, 2, 21, 21, 2, 2,
+ 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 22, 2, 22, 22, 22, 22,
+ 2, 2, 2, 22, 22, 2, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
+ 22, 22, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 23,
+ 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 2, 2, 23, 23, 2, 2,
+ 2, 23, 16, 16, 16, 16, 16, 2, 16, 16, 2, 16, 16, 16, 16, 16,
+ 2, 2, 2, 16, 16, 2, 2, 2, 16, 16, 20, 20, 20, 20, 20, 2,
+ 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 2, 2, 2, 36, 36, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2,
+ 36, 2, 2, 2, 2, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 2, 18,
+ 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 2, 18,
+ 2, 18, 18, 18, 2, 2, 18, 2, 18, 2, 25, 25, 25, 25, 2, 25,
+ 25, 25, 25, 2, 2, 2, 25, 2, 25, 25, 25, 0, 0, 0, 0, 25,
+ 25, 2, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 2, 8, 2, 8,
+ 2, 2, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 30, 2,
+ 30, 30, 30, 30, 2, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 2,
+ 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 34, 34,
+ 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0,
+ 35, 35, 35, 2, 2, 2, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
+ 2, 45, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 46, 46,
+ 46, 46, 46, 2, 46, 46, 31, 31, 31, 31, 31, 31, 2, 2, 32, 32,
+ 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 32, 2,
+ 2, 2, 32, 32, 32, 2, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48,
+ 48, 2, 48, 2, 2, 2, 52, 52, 52, 52, 52, 52, 2, 2, 52, 2,
+ 2, 2, 58, 58, 58, 58, 58, 58, 2, 2, 58, 58, 58, 2, 2, 2,
+ 58, 58, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91,
+ 91, 2, 91, 2, 2, 91, 91, 91, 2, 2, 1, 1, 1, 2, 62, 62,
+ 62, 62, 62, 2, 2, 2, 62, 62, 62, 2, 76, 76, 76, 76, 93, 93,
+ 93, 93, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 2, 2, 2, 70,
+ 70, 70, 73, 73, 73, 73, 6, 2, 2, 2, 8, 8, 8, 2, 2, 8,
+ 8, 8, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 0, 1, 1, 0, 2, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9,
+ 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19,
+ 19, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 9, 9, 1, 1,
+ 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 19, 0, 0,
+ 0, 2, 19, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2, 0, 0,
+ 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 2, 2, 0, 0, 0, 0,
+ 2, 0, 56, 56, 56, 56, 2, 55, 55, 55, 61, 61, 61, 61, 2, 2,
+ 2, 61, 61, 2, 2, 2, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13,
+ 2, 13, 13, 13, 2, 2, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13,
+ 1, 1, 1, 1, 12, 12, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17,
- 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17,
- 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2,
- 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86,
- 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2,
- 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19,
- 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
- 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2,
- 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2,
- 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2,
- 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2,
- 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68,
- 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92,
- 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2,
- 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2,
- 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12,
- 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2,
- 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2,
- 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
- 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0,
- 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2,
- 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12,
- 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0,
- 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49,
- 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2,
- 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2,
- 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2,
- 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41,
- 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,
- 118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59,
- 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51,
- 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,
- 135,135,135,135,135,135, 2, 2, 2, 2,106,106,106,106,106,106,
- 106,106,104,104,104,104,104,104,104,104,104,104,104,104, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,161,161,161,161,
- 161,161,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161,
- 2,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161, 2,
- 2, 2,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
- 110, 2,110,110,110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19,
- 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47,
- 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2,
- 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 2, 81,120,120,120,120,120,120,120,120,116,116,116,116,116,116,
- 116,116,116,116,116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2,
- 2,116,128,128,128,128,128,128,128,128,128,128,128, 2,128,128,
- 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72,
- 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98,
- 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97,
- 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57,
- 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57,
- 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2,
- 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88,
- 88, 88,117,117,117,117,117,117,117,117,112,112,112,112,112,112,
- 112,112,112,112,112,112,112,112,112, 2, 2, 2, 2,112,112,112,
- 112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,
- 122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2,
- 2, 2, 2,122,122,122,122,122,122,122, 89, 89, 89, 89, 89, 89,
- 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,
- 130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,
- 130,130,144,144,144,144,144,144,144,144,144,144, 2, 2, 2, 2,
- 2, 2,156,156,156,156,156,156,156,156,156,156, 2,156,156,156,
- 2, 2,156,156, 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,
- 147,147,148,148,148,148,148,148,148,148,148,148, 2, 2, 2, 2,
- 2, 2,158,158,158,158,158,158,158,158,158,158, 2, 2, 2, 2,
- 2, 2,153,153,153,153,153,153,153,153,153,153,153,153, 2, 2,
- 2, 2,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
- 149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2,
- 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,
- 101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2,
- 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2,
- 96, 96,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
- 111, 2,100,100,100,100,100,100,100,100, 2, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,
- 108,108,108,108, 2,108,108,108,108,108,108,108,108,108,108,108,
- 108, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129,
- 2,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
- 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,
- 109,109,109,109,109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2,
- 2, 2,107,107,107,107, 2,107,107,107,107,107,107,107,107, 2,
- 2,107,107, 2, 2,107,107,107,107,107,107,107,107,107,107,107,
- 107,107,107, 2,107,107,107,107,107,107,107, 2,107,107, 2,107,
- 107,107,107,107, 2, 1,107,107,107,107,107, 2, 2,107,107,107,
- 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,
- 107,107,107,107,107,107, 2, 2,107,107,107,107,107,107,107, 2,
- 2, 2,137,137,137,137,137,137,137,137,137,137,137,137, 2,137,
- 137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,
- 124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,
- 123,123,123,123,123,123,123,123, 2, 2,114,114,114,114,114,114,
- 114,114,114,114,114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2,
- 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,
- 102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,
- 126,126,126,126,126, 2, 2,126,126,126,126,126,126,126, 2, 2,
- 2, 2,126,126,126,126,126,126,126, 2,142,142,142,142,142,142,
- 142,142,142,142,142,142, 2, 2, 2, 2,125,125,125,125,125,125,
- 125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2,154,154,
- 154,154,154,154,154,154, 2,154,154, 2,154,154,154,154,154,154,
- 154,154,154,154,154,154,154,154, 2,154,154, 2, 2,154,154,154,
- 154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,
- 150,150, 2, 2,150,150,150,150,150,150,150,150,150,150,150, 2,
- 2, 2,141,141,141,141,141,141,141,141,140,140,140,140,140,140,
- 140,140,140,140,140, 2, 2, 2, 2, 2,121,121,121,121,121,121,
- 121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,
- 133,133,133, 2,133,133,133,133,133,133,133,133,133,133,133,133,
- 133, 2,133,133,133,133,133,133, 2, 2,133,133,133,133,133, 2,
- 2, 2,134,134,134,134,134,134,134,134, 2, 2,134,134,134,134,
- 134,134, 2,134,134,134,134,134,134,134,134,134,134,134,134,134,
- 134, 2,138,138,138,138,138,138,138, 2,138,138, 2,138,138,138,
- 138,138,138,138,138,138,138,138,138,138, 2, 2,138, 2,138,138,
- 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,
- 2,143,143, 2,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143,143,143,143,143, 2,143,143, 2,143,143,143,
- 143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2,
- 2, 2,145,145,145,145,145,145,145,145,145, 2, 2, 2, 2, 2,
- 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63,
- 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2,
- 2, 2,157,157,157,157,157,157,157,157,157,157,157, 2, 2, 2,
- 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 2, 80, 2, 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,
- 127,127,127,127,127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2,
- 2, 2,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
- 115, 2,115,115, 2, 2, 2, 2,115,115,159,159,159,159,159,159,
- 159,159,159,159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2,
- 2, 2,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
- 2, 2,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
- 2, 2,119,119, 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,
- 119,119,146,146,146,146,146,146,146,146,146,146,146, 2, 2, 2,
- 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2,
- 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2,
- 2, 2,136,136,136,136,136,136,136,136,155,155,155,155,155,155,
- 155,155,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2,
- 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17,
- 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2,
- 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17,
- 17, 17,139,139,139,139,139,139,139,139,139,139,139,139, 2, 2,
- 2, 2,105,105,105,105,105,105,105,105,105,105,105, 2, 2, 2,
- 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2,
- 2, 2,105,105, 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0,
- 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,
- 131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,
- 131,131, 2,131,131,131,131,131,131,131, 56, 56, 56, 56, 56, 56,
- 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2,
- 56, 56, 56, 56, 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,
- 151,151,151,151,151,151,151, 2, 2, 2,151,151,151,151,151,151,
+ 17, 17, 17, 17, 17, 0, 2, 26, 26, 26, 26, 26, 26, 26, 2, 12,
+ 12, 12, 12, 12, 12, 2, 12, 12, 12, 0, 39, 39, 39, 39, 39, 2,
+ 2, 2, 39, 39, 39, 2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79,
+ 79, 79, 19, 19, 19, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
+ 2, 2, 2, 2, 19, 19, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65,
+ 65, 65, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 75, 75, 69, 69,
+ 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 2, 2, 2, 74, 12, 2,
+ 2, 2, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2,
+ 84, 84, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68,
+ 2, 2, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 92, 87, 87,
+ 87, 87, 87, 87, 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 87, 87,
+ 2, 2, 2, 2, 2, 12, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14,
+ 2, 14, 14, 2, 14, 14, 2, 2, 2, 3, 3, 3, 0, 0, 2, 2,
+ 3, 3, 1, 1, 6, 6, 3, 2, 3, 3, 3, 2, 2, 0, 2, 0,
+ 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 49, 49,
+ 49, 49, 2, 49, 49, 49, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
+ 2, 2, 9, 2, 2, 2, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2,
+ 2, 2, 67, 67, 67, 67, 67, 2, 2, 2, 42, 42, 42, 42, 2, 42,
+ 42, 42, 41, 41, 41, 41, 41, 41, 41, 2,118,118,118,118,118,118,
+ 118, 2, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59,
+ 2, 2, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50,
+ 2, 2,135,135,135,135,106,106,106,106,104,104,104,104, 2, 2,
+ 2,104,161,161,161,161,161,161,161, 2,161,161, 2,161,161, 2,
+ 2, 2,110,110,110,110,110,110,110, 2,110,110, 2, 2, 19, 2,
+ 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47,
+ 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81,
+ 2, 81,120,120,120,120,116,116,116,116,116,116,116, 2, 2, 2,
+ 2,116,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
+ 2,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72,
+ 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 97, 97, 97, 97, 2, 2,
+ 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 57, 57, 57, 57, 57,
+ 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 88, 88,
+ 88, 88,117,117,117,117,112,112,112,112,112,112,112, 2, 2, 2,
+ 2,112, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83,
+ 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 2,122,122,
+ 122,122,122,122, 2, 2, 2,122,122,122,122, 2, 2, 2, 89, 89,
+ 89, 89, 89, 2, 2, 2,130,130,130,130,130,130,130, 2, 2, 2,
+ 130,130,144,144,144,144,144,144, 2, 2,156,156,156,156,156,156,
+ 2,156,156,156, 2, 2, 2, 3, 3, 3,147,147,147,147,148,148,
+ 148,148,148,148, 2, 2,158,158,158,158,158,158, 2, 2,153,153,
+ 153,153,149,149,149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94,
+ 2, 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85,
+ 85, 2, 2, 85, 2, 2,101,101,101,101,101, 2, 2, 2,101,101,
+ 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,
+ 111, 2,100,100,100,100,108,108,108,108,108,108, 2,108,108,108,
+ 2, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129,
+ 2,129,129,129, 2, 2,109,109,109,109,109,109,109, 2,109,109,
+ 2, 2,107,107,107,107, 2,107,107,107,107, 2, 2,107,107, 2,
+ 107,107,107,107, 2, 1,107,107, 2, 2,107, 2, 2, 2, 2, 2,
+ 2,107, 2, 2,107,107,137,137,137,137, 2,137,137,137,137,137,
+ 2, 2,124,124,124,124,124,124, 2, 2,123,123,123,123,123,123,
+ 2, 2,114,114,114,114,114, 2, 2, 2,114,114, 2, 2,102,102,
+ 102,102,102,102, 2, 2,126,126,126,126,126,126,126, 2, 2,126,
+ 126,126,142,142,142,142,125,125,125,125,125,125,125, 2, 2, 2,
+ 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2, 2,154,
+ 154, 2,154,154, 2,154,154, 2, 2,154,154,154, 2, 2,150,150,
+ 150,150, 2, 2,150,150,150, 2, 2, 2,141,141,141,141,140,140,
+ 140,140,140,140,140, 2,121,121,121,121,121, 2, 2, 2, 7, 7,
+ 2, 2,133,133,133,133,133, 2,133,133,133,133,133, 2,133,133,
+ 2, 2,133, 2, 2, 2,134,134,134,134, 2, 2,134,134, 2,134,
+ 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138,
+ 2,138, 2, 2,138, 2,138,138, 2, 2,143,143,143,143,143,143,
+ 2,143,143, 2,143,143,143,143,143, 2,143, 2, 2, 2,143,143,
+ 2, 2,145,145,145,145,145, 2, 2, 2,163,163,163,163,163, 2,
+ 163,163,163,163,163, 2, 2, 2,163,163,163,163, 2, 2, 86, 2,
+ 2, 2, 63, 63, 63, 63, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2,
+ 2, 2,157,157,157,157,157,157,157, 2, 80, 80, 80, 80, 80, 80,
+ 2, 2,127,127,127,127,127,127,127, 2, 79, 2, 2, 2,115,115,
+ 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
+ 159,159,159,159,159, 2,159,159, 2, 2,103,103,103,103,103,103,
+ 2, 2,119,119,119,119,119,119, 2, 2,119,119, 2,119, 2,119,
+ 119,119,146,146,146,146,146,146,146, 2, 99, 99, 99, 99, 99, 99,
+ 99, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
+ 136,136,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 17,
+ 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, 17, 2, 2, 2,
+ 15, 2, 2, 17, 2, 2,139,139,139,139,105,105,105,105,105,105,
+ 105, 2,105, 2, 2, 2,105,105, 2, 2, 1, 1, 2, 2, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, 0, 2, 2, 0,
+ 0, 2, 0, 2, 0, 2,131,131,131,131, 2, 2, 2,131, 2,131,
+ 131,131, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 2, 56, 56, 2,
+ 56, 56, 6, 6, 2, 2, 2, 2, 2, 6,151,151,151,151,151, 2,
2, 2,151,151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,
- 160,160,160,160,160,160,160,160,160, 2,152,152,152,152,152,152,
- 152,152,152,152, 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30,
- 30, 2,113,113,113,113,113,113,113,113,113,113,113,113,113, 2,
- 2,113,113,113,113,113,113,113,113, 2,132,132,132,132,132,132,
- 132,132,132,132,132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,
- 132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2,
- 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
- 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2,
- 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3,
- 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2,
- 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
- 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10,
- 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9,
+ 160, 2,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
+ 164,164,164,164, 2, 2, 2, 30, 30, 2,113,113,113,113,113, 2,
+ 2,113,113,113,113, 2,132,132,132,132,132,132, 2, 2, 2, 2,
+ 132,132, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 2,
+ 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 15, 0, 0, 2, 13, 2,
+ 2, 2, 13, 13, 13, 2, 2, 0, 2, 2, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14,
+ 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9,
+ 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9,
+ 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -4993,60 +3702,60 @@ _hb_ucd_u8[17936] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0,
- 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24,
+ 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35,
+ 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0,
- 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0,
- 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0,
- 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0,
+ 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0,
+ 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0,
+ 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61,
+ 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0,
- 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0,
+ 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,
+ 113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 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,100,101,102,
- 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,
- 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0,
- 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0,
+ 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121,
+ 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127,
+ 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0,
- 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0,
- 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0,
+ 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0,
+ 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,177,178,179,180,
+ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,
+ 197,198,199,200,201,202,203,204,205,206, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,
- 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
- 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
- 205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[9200] =
+_hb_ucd_u16[10040] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -5120,537 +3829,583 @@ _hb_ucd_u16[9200] =
48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
- 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48,
- 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487,
- 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494,
- 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140,
- 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512,
- 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
- 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140,
- 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140,
- 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
- 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
- 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
- 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
- 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560,
- 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562,
- 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
- 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
- 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
- 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
+ 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48,
+ 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488,
+ 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495,
+ 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140,
+ 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514,
+ 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140,
+ 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140,
+ 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140,
+ 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532,
+ 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140,
+ 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196,
+ 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550,
+ 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48,
+ 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560,
+ 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+ 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+ 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569,
+ 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
+ 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573,
+ 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140,
- 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
- 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206,
- 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
- 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588,
- 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461,
- 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
- 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
- 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
- 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
- 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
- 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140,
- 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
- 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140,
- 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498,
- 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140,
- 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
- 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
- 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662,
- 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323,
- 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209,
- 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665,
- 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192,
- 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48,
+ 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+ 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206,
+ 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+ 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+ 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+ 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+ 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+ 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11,
+ 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11,
+ 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623,
+ 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632,
+ 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140,
+ 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140,
+ 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140,
+ 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192,
+ 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140,
+ 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+ 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+ 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+ 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
+ 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
+ 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
+ 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
+ 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
+ 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
+ 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
- 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3,
- 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11,
- 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21,
- 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26,
- 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31,
- 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31,
- 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43,
- 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31,
- 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53,
- 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67,
- 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26,
- 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91,
- 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26,
- 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112,
- 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
- 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26,
- 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
- 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26,
- 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26,
- 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26,
- 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157,
- 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26,
- 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
- 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169,
- 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169,
- 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173,
- 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176,
- 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
- 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182,
- 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26,
- 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195,
- 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199,
- 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26,
- 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26,
- 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193,
- 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217,
- 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26,
- 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223,
- 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
- 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
- 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238,
- 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244,
- 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9,
- 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246,
- 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252,
- 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256,
- 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26,
- 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2,
- 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
+ 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
+ 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 1, 2, 1, 2,
+ 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9,
+ 10, 11, 12, 11, 11, 11, 13, 11, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 16, 17, 18, 17, 17,
+ 19, 20, 21, 21, 22, 21, 23, 24, 25, 26, 27, 27, 28, 29, 27, 30,
+ 27, 27, 27, 27, 27, 31, 27, 27, 32, 33, 33, 33, 34, 27, 27, 27,
+ 35, 35, 35, 36, 37, 37, 37, 38, 39, 39, 40, 41, 42, 43, 44, 27,
+ 45, 46, 27, 27, 27, 27, 47, 27, 48, 48, 48, 48, 48, 49, 50, 48,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 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, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112, 109,
+ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 122, 124, 125, 125,
+ 126, 127, 128, 129, 130, 131, 125, 125, 132, 132, 132, 132, 133, 132, 134, 135,
+ 132, 133, 132, 136, 136, 137, 125, 125, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 139, 139, 140, 139, 139, 141, 142, 142, 142, 142, 142, 142, 142, 142,
+ 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
+ 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
+ 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
+ 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
+ 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
+ 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 8, 195, 125, 125, 125,
+ 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
+ 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
+ 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 8,
+ 11, 217, 11, 11, 217, 218, 11, 219, 11, 11, 11, 220, 220, 221, 11, 222,
+ 223, 0, 0, 0, 0, 0, 224, 225, 226, 227, 0, 0, 228, 8, 8, 229,
+ 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 125, 235, 125, 0, 0,
+ 236, 236, 236, 236, 236, 236, 236, 236, 0, 0, 0, 0, 0, 0, 0, 237,
+ 0, 238, 0, 0, 0, 0, 0, 0, 239, 239, 239, 239, 239, 239, 4, 4,
+ 240, 240, 240, 240, 240, 240, 240, 241, 139, 139, 140, 242, 242, 242, 243, 244,
+ 143, 245, 246, 246, 246, 246, 14, 14, 0, 0, 0, 0, 0, 247, 125, 125,
+ 248, 249, 248, 248, 248, 248, 248, 250, 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 251, 125, 252, 253, 0, 254, 255, 256, 257, 257, 257,
+ 257, 258, 259, 260, 260, 260, 260, 261, 262, 263, 263, 264, 142, 142, 142, 142,
+ 265, 0, 263, 263, 0, 0, 266, 260, 142, 265, 0, 0, 0, 0, 142, 267,
+ 0, 0, 0, 0, 0, 260, 260, 268, 260, 260, 260, 260, 260, 269, 0, 0,
+ 248, 248, 248, 248, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
+ 271, 270, 270, 270, 272, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274,
+ 274, 274, 275, 125, 14, 14, 14, 14, 14, 14, 276, 276, 276, 276, 276, 277,
+ 0, 0, 278, 4, 4, 4, 4, 4, 279, 4, 4, 4, 280, 281, 125, 282,
+ 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 48, 48,
+ 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
+ 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
+ 309, 310, 246, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
+ 142, 142, 315, 142, 316, 142, 142, 317, 125, 125, 125, 125, 125, 125, 125, 125,
+ 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
+ 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 325, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 326, 27, 27, 27, 27,
+ 27, 327, 27, 27, 328, 125, 125, 27, 8, 285, 329, 0, 0, 330, 331, 332,
+ 27, 27, 27, 27, 27, 27, 27, 333, 334, 0, 1, 2, 1, 2, 335, 259,
+ 260, 336, 142, 265, 337, 338, 339, 340, 341, 342, 343, 344, 345, 345, 125, 125,
+ 342, 342, 342, 342, 342, 342, 342, 346, 347, 0, 0, 348, 11, 11, 11, 11,
+ 349, 350, 351, 125, 125, 0, 0, 352, 353, 354, 355, 355, 355, 356, 357, 252,
+ 358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
+ 369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
+ 377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
+ 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 386, 385, 387, 388, 125,
+ 389, 4, 4, 390, 125, 125, 125, 125, 391, 392, 392, 393, 394, 395, 396, 396,
+ 397, 398, 399, 125, 125, 125, 400, 401, 402, 403, 404, 405, 125, 125, 125, 125,
+ 406, 406, 407, 408, 407, 409, 407, 407, 410, 411, 412, 413, 414, 414, 415, 415,
+ 416, 416, 125, 125, 417, 417, 418, 419, 420, 420, 420, 421, 422, 423, 424, 425,
+ 426, 427, 428, 125, 125, 125, 125, 125, 429, 429, 429, 429, 430, 125, 125, 125,
+ 431, 431, 431, 432, 431, 431, 431, 433, 434, 434, 435, 436, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 27, 45, 437, 437, 438, 439, 125, 125, 125, 440,
+ 441, 441, 442, 443, 443, 444, 125, 445, 446, 125, 125, 447, 448, 125, 449, 450,
+ 451, 451, 451, 451, 452, 453, 451, 454, 455, 455, 455, 455, 456, 457, 458, 459,
+ 460, 460, 460, 461, 462, 463, 463, 464, 465, 465, 465, 465, 465, 465, 466, 467,
+ 468, 469, 468, 468, 470, 125, 125, 125, 471, 472, 473, 474, 474, 474, 475, 476,
+ 477, 478, 479, 480, 481, 482, 483, 484, 485, 485, 485, 485, 485, 486, 487, 125,
+ 488, 488, 488, 488, 489, 490, 125, 125, 491, 491, 491, 492, 491, 493, 125, 125,
+ 494, 494, 494, 494, 495, 496, 497, 125, 498, 498, 498, 499, 499, 125, 125, 125,
+ 500, 501, 502, 500, 503, 125, 125, 125, 504, 504, 504, 505, 125, 125, 125, 125,
+ 125, 125, 506, 506, 506, 506, 506, 507, 508, 509, 510, 511, 512, 513, 125, 125,
+ 125, 125, 514, 515, 515, 514, 516, 125, 517, 517, 517, 517, 518, 519, 519, 519,
+ 519, 519, 520, 154, 521, 521, 521, 522, 523, 125, 125, 125, 125, 125, 125, 125,
+ 524, 525, 525, 526, 527, 525, 528, 529, 529, 530, 531, 532, 125, 125, 125, 125,
+ 533, 534, 534, 535, 536, 537, 538, 539, 540, 541, 542, 125, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 543, 544, 545, 546, 545, 547, 545, 548, 125, 125,
+ 125, 125, 125, 549, 550, 550, 550, 551, 552, 552, 552, 552, 552, 552, 552, 552,
+ 552, 553, 125, 125, 125, 125, 125, 125, 552, 552, 552, 552, 552, 552, 554, 555,
+ 552, 552, 552, 552, 556, 125, 125, 125, 125, 557, 557, 557, 557, 557, 557, 558,
+ 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 560, 125, 125,
+ 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562, 125, 125, 125,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 563, 564, 565, 566, 567,
+ 567, 567, 567, 568, 569, 570, 571, 572, 573, 573, 573, 573, 574, 575, 576, 577,
+ 573, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 578, 578, 578, 578,
+ 578, 579, 125, 125, 125, 125, 125, 125, 580, 580, 580, 580, 581, 580, 580, 580,
+ 582, 580, 125, 125, 125, 125, 583, 584, 585, 585, 585, 585, 585, 585, 585, 585,
+ 585, 585, 585, 585, 585, 585, 585, 586, 587, 587, 587, 587, 587, 587, 587, 587,
+ 587, 587, 587, 587, 587, 588, 125, 125, 589, 125, 125, 125, 125, 125, 125, 125,
+ 125, 125, 125, 125, 125, 125, 125, 590, 591, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 592, 593, 125, 594, 595, 596,
+ 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597,
+ 598, 598, 598, 598, 598, 598, 599, 600, 601, 602, 266, 125, 125, 125, 125, 125,
+ 8, 8, 603, 8, 604, 0, 0, 0, 0, 0, 0, 0, 266, 125, 125, 125,
+ 0, 0, 0, 0, 0, 0, 0, 605, 0, 0, 606, 0, 0, 0, 607, 608,
+ 609, 0, 610, 0, 0, 0, 235, 125, 11, 11, 11, 11, 611, 125, 125, 125,
+ 125, 125, 125, 125, 0, 266, 0, 266, 0, 0, 0, 0, 0, 234, 0, 612,
+ 0, 0, 0, 0, 0, 224, 0, 0, 0, 613, 614, 615, 616, 0, 0, 0,
+ 617, 618, 0, 619, 620, 621, 0, 0, 0, 0, 622, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 623, 0, 0, 0, 624, 624, 624, 624, 624, 624, 624, 624,
+ 625, 626, 627, 125, 125, 125, 125, 125, 4, 628, 629, 125, 125, 125, 125, 125,
+ 630, 631, 632, 14, 14, 14, 633, 125, 634, 125, 125, 125, 125, 125, 125, 125,
+ 635, 635, 636, 637, 638, 125, 125, 125, 125, 639, 640, 125, 641, 641, 641, 642,
+ 125, 125, 125, 125, 125, 643, 643, 644, 125, 125, 125, 125, 125, 125, 645, 646,
+ 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 648, 649, 125, 125,
+ 650, 650, 650, 650, 651, 652, 125, 125, 125, 125, 125, 125, 125, 125, 125, 334,
+ 0, 0, 0, 653, 125, 125, 125, 125, 334, 0, 0, 247, 125, 125, 125, 125,
+ 654, 27, 655, 656, 657, 658, 659, 660, 661, 662, 663, 662, 125, 125, 125, 664,
+ 0, 0, 252, 0, 0, 0, 0, 0, 0, 266, 226, 334, 334, 334, 0, 605,
+ 0, 0, 247, 125, 125, 125, 665, 0, 666, 0, 0, 252, 612, 667, 605, 125,
+ 0, 0, 0, 0, 0, 668, 350, 350, 0, 0, 0, 0, 0, 0, 0, 669,
+ 0, 0, 0, 0, 0, 285, 252, 228, 252, 0, 0, 0, 670, 285, 0, 0,
+ 670, 0, 247, 667, 125, 125, 125, 125, 0, 0, 0, 0, 0, 266, 247, 350,
+ 612, 0, 0, 671, 672, 252, 612, 612, 0, 330, 0, 0, 235, 125, 125, 285,
+ 248, 248, 248, 248, 248, 248, 125, 125, 248, 248, 248, 319, 248, 248, 248, 248,
+ 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 584, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 673, 125, 248, 318, 125, 125, 125, 125, 125, 125,
+ 248, 248, 248, 248, 674, 248, 248, 248, 248, 248, 248, 125, 125, 125, 125, 125,
+ 675, 125, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 1, 2, 2, 2,
+ 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2,
+ 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 8, 8, 8, 8, 16, 8, 8, 8, 17, 18, 18, 18,
+ 19, 19, 19, 19, 19, 20, 19, 19, 21, 22, 22, 22, 22, 22, 22, 22,
+ 22, 23, 21, 22, 22, 22, 23, 21, 24, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 12, 12, 25, 25, 26, 27, 25, 28, 12, 12, 29, 30, 29, 31,
+ 29, 29, 32, 32, 29, 29, 29, 29, 31, 29, 33, 7, 7, 34, 29, 29,
+ 35, 29, 29, 29, 29, 29, 29, 30, 36, 36, 36, 37, 36, 36, 36, 36,
+ 36, 36, 38, 39, 40, 40, 40, 40, 41, 12, 12, 12, 42, 42, 42, 42,
+ 42, 42, 43, 44, 45, 45, 45, 45, 45, 45, 45, 46, 45, 45, 45, 47,
+ 48, 48, 48, 48, 48, 48, 48, 49, 36, 36, 38, 12, 29, 29, 29, 50,
+ 51, 12, 29, 29, 52, 29, 29, 29, 53, 53, 53, 53, 54, 55, 53, 53,
+ 53, 56, 53, 53, 57, 58, 57, 59, 59, 57, 57, 57, 57, 57, 60, 57,
+ 61, 62, 63, 57, 57, 59, 59, 64, 12, 65, 12, 66, 57, 62, 57, 57,
+ 57, 57, 57, 64, 67, 67, 68, 69, 70, 71, 71, 71, 71, 71, 72, 71,
+ 72, 73, 74, 72, 68, 69, 70, 74, 75, 12, 67, 76, 12, 77, 71, 71,
+ 71, 68, 12, 12, 78, 78, 79, 80, 80, 79, 79, 79, 79, 79, 81, 79,
+ 81, 78, 82, 79, 79, 80, 80, 82, 83, 12, 12, 12, 79, 84, 79, 79,
+ 82, 12, 78, 79, 85, 85, 86, 87, 87, 86, 86, 86, 86, 86, 88, 86,
+ 88, 85, 89, 86, 86, 87, 87, 89, 12, 85, 12, 90, 86, 91, 86, 86,
+ 86, 86, 12, 12, 92, 93, 94, 92, 95, 96, 97, 95, 98, 99, 94, 92,
+ 100, 100, 96, 92, 94, 92, 95, 96, 99, 98, 12, 12, 12, 92, 100, 100,
+ 100, 100, 94, 12, 101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101,
+ 101, 101, 103, 101, 101, 102, 102, 103, 12, 104, 105, 106, 101, 107, 101, 101,
+ 12, 108, 101, 101, 109, 109, 109, 110, 110, 109, 109, 109, 109, 109, 110, 109,
+ 109, 111, 112, 109, 109, 110, 110, 112, 12, 113, 12, 113, 109, 114, 109, 109,
+ 111, 12, 12, 12, 115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115,
+ 115, 116, 116, 115, 12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119,
+ 119, 120, 121, 119, 119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125,
+ 119, 126, 119, 119, 12, 121, 119, 119, 121, 127, 12, 12, 128, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 130, 131, 129, 129, 129, 12, 12, 12, 12, 12,
+ 132, 133, 134, 135, 135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137,
+ 135, 138, 135, 134, 135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139,
+ 139, 139, 139, 141, 140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144, 12,
+ 145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 12, 148, 146, 146, 149, 146,
+ 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153,
+ 152, 153, 151, 154, 152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155,
+ 151, 151, 151, 156, 151, 151, 153, 12, 157, 157, 157, 157, 157, 158, 157, 158,
+ 159, 159, 159, 159, 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162,
+ 162, 162, 163, 164, 162, 162, 165, 12, 166, 166, 166, 166, 166, 167, 12, 168,
+ 169, 169, 169, 169, 169, 170, 12, 12, 171, 171, 171, 171, 171, 12, 12, 12,
+ 172, 172, 172, 173, 173, 12, 12, 12, 174, 174, 174, 174, 174, 174, 174, 175,
+ 174, 174, 175, 12, 176, 177, 178, 178, 178, 178, 179, 12, 178, 178, 178, 178,
+ 178, 178, 180, 12, 178, 178, 181, 12, 159, 182, 12, 12, 183, 183, 183, 183,
+ 183, 183, 183, 184, 183, 183, 183, 12, 185, 183, 183, 183, 186, 186, 186, 186,
+ 186, 186, 186, 187, 186, 188, 12, 12, 189, 189, 189, 189, 189, 189, 189, 12,
+ 189, 189, 190, 12, 189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194,
+ 195, 195, 195, 195, 195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198, 12,
+ 195, 195, 195, 198, 7, 7, 7, 199, 200, 200, 200, 200, 200, 200, 200, 201,
+ 200, 200, 200, 202, 203, 203, 203, 203, 204, 204, 204, 204, 204, 12, 12, 204,
+ 205, 205, 205, 205, 205, 205, 206, 205, 205, 205, 207, 208, 209, 209, 209, 209,
+ 19, 19, 210, 12, 146, 146, 211, 212, 203, 203, 12, 12, 213, 7, 7, 7,
+ 214, 7, 215, 216, 0, 215, 217, 12, 2, 218, 219, 2, 2, 2, 2, 220,
+ 221, 218, 222, 2, 2, 2, 223, 2, 2, 2, 2, 224, 8, 225, 8, 225,
+ 8, 8, 226, 226, 8, 8, 8, 225, 8, 15, 8, 8, 8, 10, 8, 227,
+ 10, 15, 8, 14, 0, 0, 0, 228, 0, 229, 0, 0, 230, 0, 0, 231,
+ 0, 0, 0, 232, 2, 2, 2, 233, 234, 12, 12, 12, 235, 12, 12, 12,
+ 0, 236, 237, 0, 4, 0, 0, 0, 0, 0, 0, 4, 2, 2, 5, 12,
+ 0, 232, 12, 12, 0, 0, 232, 12, 238, 238, 238, 238, 0, 239, 0, 0,
+ 0, 240, 0, 0, 241, 241, 241, 241, 18, 18, 18, 18, 18, 12, 242, 18,
+ 243, 243, 243, 243, 243, 243, 12, 244, 245, 12, 12, 244, 151, 154, 12, 12,
+ 151, 154, 151, 154, 0, 0, 0, 246, 247, 247, 247, 247, 247, 247, 248, 247,
+ 247, 12, 12, 12, 247, 249, 12, 12, 0, 0, 0, 12, 0, 250, 0, 0,
+ 251, 247, 252, 253, 0, 0, 247, 0, 254, 255, 255, 255, 255, 255, 255, 255,
+ 255, 256, 257, 258, 259, 260, 260, 260, 260, 260, 260, 260, 260, 260, 261, 259,
+ 12, 262, 263, 263, 263, 263, 263, 263, 264, 150, 150, 150, 150, 150, 150, 265,
+ 0, 12, 12, 12, 150, 150, 150, 266, 260, 260, 260, 261, 260, 260, 0, 0,
+ 267, 267, 267, 267, 267, 267, 267, 268, 267, 269, 12, 12, 270, 270, 270, 270,
+ 271, 271, 271, 271, 271, 271, 271, 12, 272, 272, 272, 272, 272, 272, 12, 12,
+ 237, 2, 2, 2, 2, 2, 231, 2, 2, 2, 273, 12, 274, 275, 276, 12,
+ 277, 2, 2, 2, 278, 278, 278, 278, 278, 278, 278, 279, 0, 0, 246, 12,
+ 280, 280, 280, 280, 280, 280, 12, 12, 281, 281, 281, 281, 281, 282, 12, 283,
+ 281, 281, 282, 12, 284, 284, 284, 284, 284, 284, 284, 285, 286, 286, 286, 286,
+ 286, 12, 12, 287, 150, 150, 150, 288, 289, 289, 289, 289, 289, 289, 289, 290,
+ 289, 289, 291, 292, 145, 145, 145, 293, 294, 294, 294, 294, 294, 295, 12, 12,
+ 294, 294, 294, 296, 294, 294, 296, 294, 297, 297, 297, 297, 298, 12, 12, 12,
+ 12, 12, 299, 297, 300, 300, 300, 300, 300, 301, 12, 12, 155, 154, 155, 154,
+ 155, 154, 12, 12, 2, 2, 3, 2, 2, 302, 303, 12, 300, 300, 300, 304,
+ 300, 300, 304, 12, 150, 12, 12, 12, 150, 265, 305, 150, 150, 150, 150, 12,
+ 247, 247, 247, 249, 247, 247, 249, 12, 2, 273, 12, 12, 306, 22, 12, 24,
+ 25, 26, 25, 307, 308, 309, 25, 25, 50, 12, 12, 12, 310, 29, 29, 29,
+ 29, 29, 29, 311, 312, 29, 29, 29, 29, 29, 12, 310, 7, 7, 7, 313,
+ 232, 0, 0, 0, 0, 232, 0, 12, 29, 314, 29, 29, 29, 29, 29, 315,
+ 316, 0, 0, 0, 0, 317, 260, 260, 260, 260, 260, 318, 319, 150, 319, 150,
+ 319, 150, 319, 288, 0, 232, 0, 232, 12, 12, 316, 246, 320, 320, 320, 321,
+ 320, 320, 320, 320, 320, 322, 320, 320, 320, 320, 322, 323, 320, 320, 320, 324,
+ 320, 320, 322, 12, 232, 131, 0, 0, 0, 131, 0, 0, 8, 8, 8, 14,
+ 0, 0, 0, 234, 325, 12, 12, 12, 0, 0, 0, 326, 327, 327, 327, 327,
+ 327, 327, 327, 328, 329, 329, 329, 329, 330, 12, 12, 12, 215, 0, 0, 0,
+ 331, 331, 331, 331, 331, 12, 12, 332, 333, 333, 333, 333, 333, 333, 334, 12,
+ 335, 335, 335, 335, 335, 335, 336, 12, 337, 337, 337, 337, 337, 337, 337, 338,
+ 339, 339, 339, 339, 339, 12, 339, 339, 339, 340, 12, 12, 341, 341, 341, 341,
+ 342, 342, 342, 342, 343, 343, 343, 343, 343, 343, 343, 344, 343, 343, 344, 12,
+ 345, 345, 345, 345, 345, 12, 345, 345, 345, 345, 345, 12, 346, 346, 346, 346,
+ 346, 346, 12, 12, 347, 347, 347, 347, 347, 12, 12, 348, 349, 349, 350, 349,
+ 350, 351, 349, 349, 351, 349, 349, 349, 351, 349, 351, 352, 353, 353, 353, 353,
+ 353, 354, 12, 12, 353, 355, 12, 12, 353, 353, 12, 12, 2, 274, 2, 2,
+ 356, 2, 273, 12, 357, 358, 359, 357, 357, 357, 357, 357, 357, 360, 361, 362,
+ 363, 363, 363, 363, 363, 364, 363, 363, 365, 365, 365, 365, 366, 366, 366, 366,
+ 366, 366, 366, 367, 12, 368, 366, 366, 369, 369, 369, 369, 370, 371, 372, 369,
+ 373, 373, 373, 373, 373, 373, 373, 374, 375, 375, 375, 375, 375, 375, 376, 377,
+ 378, 378, 378, 378, 379, 379, 379, 379, 379, 379, 12, 379, 380, 379, 379, 379,
+ 381, 382, 12, 381, 381, 383, 383, 381, 381, 381, 381, 381, 381, 384, 385, 386,
+ 381, 381, 387, 12, 388, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, 390,
+ 390, 391, 392, 390, 390, 391, 12, 12, 393, 393, 393, 393, 393, 394, 395, 393,
+ 396, 396, 396, 396, 396, 397, 396, 396, 398, 398, 398, 398, 399, 12, 398, 398,
+ 400, 400, 400, 400, 401, 12, 402, 403, 12, 12, 402, 400, 404, 404, 404, 404,
+ 404, 404, 405, 12, 406, 406, 406, 406, 407, 12, 12, 12, 407, 12, 408, 406,
+ 409, 409, 409, 409, 409, 409, 12, 12, 409, 409, 410, 12, 411, 411, 411, 411,
+ 411, 411, 412, 413, 413, 12, 12, 12, 12, 12, 12, 414, 415, 415, 415, 415,
+ 415, 415, 12, 12, 416, 416, 416, 416, 416, 416, 417, 12, 418, 418, 418, 418,
+ 418, 418, 419, 12, 420, 420, 420, 420, 420, 420, 420, 12, 421, 421, 421, 421,
+ 421, 422, 12, 12, 423, 423, 423, 423, 423, 423, 423, 424, 425, 423, 423, 423,
+ 423, 424, 12, 426, 427, 427, 427, 427, 428, 12, 12, 429, 430, 430, 430, 430,
+ 430, 430, 431, 12, 430, 430, 432, 12, 433, 433, 433, 433, 433, 434, 433, 433,
+ 433, 433, 12, 12, 435, 435, 435, 435, 435, 436, 12, 12, 437, 437, 437, 437,
+ 118, 119, 119, 119, 119, 127, 12, 12, 438, 438, 438, 438, 439, 438, 438, 438,
+ 440, 12, 12, 12, 441, 442, 443, 444, 441, 441, 441, 444, 441, 441, 445, 12,
+ 446, 446, 446, 446, 446, 446, 447, 12, 446, 446, 448, 12, 449, 450, 449, 451,
+ 451, 449, 449, 449, 449, 449, 452, 449, 452, 450, 453, 449, 449, 451, 451, 454,
+ 455, 456, 12, 450, 449, 457, 449, 455, 449, 455, 12, 12, 458, 458, 458, 458,
+ 458, 458, 458, 459, 460, 12, 12, 12, 461, 461, 461, 461, 461, 461, 12, 12,
+ 461, 461, 462, 12, 463, 463, 463, 463, 463, 464, 463, 463, 463, 463, 463, 464,
+ 465, 465, 465, 465, 465, 466, 12, 12, 465, 465, 467, 12, 178, 178, 178, 180,
+ 468, 468, 468, 468, 468, 468, 469, 12, 470, 470, 470, 470, 470, 470, 471, 472,
+ 470, 470, 470, 12, 470, 471, 12, 12, 473, 473, 473, 473, 473, 473, 473, 12,
+ 474, 474, 474, 474, 475, 12, 12, 476, 477, 478, 479, 477, 477, 480, 477, 477,
+ 477, 477, 477, 477, 477, 481, 482, 477, 477, 478, 12, 12, 477, 477, 483, 12,
+ 484, 484, 485, 484, 484, 484, 484, 484, 484, 486, 12, 12, 487, 487, 487, 487,
+ 487, 487, 12, 12, 488, 488, 488, 488, 489, 12, 12, 12, 490, 490, 490, 490,
+ 490, 490, 491, 12, 53, 53, 492, 12, 493, 493, 494, 493, 493, 493, 493, 493,
+ 493, 495, 493, 493, 493, 496, 12, 12, 493, 493, 493, 497, 498, 498, 498, 498,
+ 499, 498, 498, 498, 498, 498, 500, 498, 498, 501, 12, 12, 502, 503, 504, 502,
+ 502, 502, 502, 502, 502, 503, 505, 504, 502, 502, 12, 12, 502, 502, 506, 12,
+ 507, 508, 509, 507, 507, 507, 507, 507, 507, 507, 507, 510, 508, 507, 511, 12,
+ 507, 507, 512, 12, 513, 513, 513, 513, 513, 513, 514, 12, 515, 515, 515, 515,
+ 516, 515, 515, 515, 515, 515, 517, 518, 515, 515, 519, 12, 520, 12, 12, 12,
+ 100, 100, 100, 100, 96, 12, 12, 98, 521, 521, 521, 521, 521, 521, 522, 12,
+ 521, 521, 521, 523, 521, 524, 12, 12, 521, 12, 12, 12, 525, 525, 525, 525,
+ 526, 12, 12, 12, 527, 527, 527, 527, 527, 528, 12, 12, 529, 529, 529, 529,
+ 529, 530, 12, 12, 272, 272, 531, 12, 532, 532, 532, 532, 532, 532, 532, 533,
+ 532, 532, 534, 535, 536, 536, 536, 536, 536, 536, 536, 537, 536, 536, 538, 12,
+ 539, 539, 539, 539, 539, 539, 539, 540, 539, 540, 12, 12, 541, 541, 541, 541,
+ 541, 542, 12, 12, 541, 541, 543, 541, 543, 541, 541, 541, 541, 541, 12, 544,
+ 545, 545, 545, 545, 545, 545, 546, 12, 547, 547, 547, 547, 547, 547, 548, 549,
+ 547, 547, 12, 549, 550, 551, 12, 12, 249, 12, 12, 12, 552, 552, 552, 552,
+ 552, 552, 12, 12, 553, 553, 553, 553, 553, 554, 12, 12, 552, 552, 555, 12,
+ 260, 556, 260, 557, 558, 255, 255, 255, 559, 12, 12, 12, 560, 12, 12, 12,
+ 256, 561, 12, 12, 12, 260, 12, 12, 562, 562, 562, 562, 562, 562, 562, 12,
+ 563, 563, 563, 563, 563, 563, 564, 12, 563, 563, 563, 565, 563, 563, 565, 12,
+ 563, 563, 566, 563, 7, 7, 7, 567, 7, 199, 12, 12, 0, 246, 12, 12,
+ 0, 232, 316, 0, 0, 568, 228, 0, 0, 0, 568, 7, 213, 569, 7, 0,
+ 0, 0, 570, 228, 8, 225, 12, 12, 0, 0, 234, 12, 0, 0, 0, 229,
+ 571, 572, 316, 229, 0, 0, 240, 316, 0, 316, 0, 0, 0, 240, 232, 316,
+ 0, 229, 0, 229, 0, 0, 240, 232, 0, 573, 239, 0, 229, 0, 0, 0,
+ 0, 246, 0, 0, 0, 0, 0, 239, 574, 574, 574, 574, 574, 574, 574, 12,
+ 12, 12, 575, 574, 576, 574, 574, 574, 2, 2, 2, 273, 12, 275, 273, 12,
+ 241, 577, 241, 241, 241, 241, 578, 241, 579, 580, 577, 12, 19, 19, 19, 581,
+ 12, 12, 12, 582, 583, 583, 583, 583, 583, 583, 583, 584, 583, 583, 583, 585,
+ 583, 583, 585, 586, 587, 587, 587, 587, 587, 587, 587, 588, 589, 589, 589, 589,
+ 589, 589, 590, 591, 592, 592, 592, 592, 592, 592, 593, 12, 151, 154, 151, 594,
+ 151, 151, 151, 154, 595, 595, 595, 595, 595, 596, 595, 595, 595, 597, 12, 12,
+ 598, 598, 598, 598, 598, 598, 598, 12, 598, 598, 599, 600, 0, 234, 12, 12,
+ 29, 414, 29, 29, 601, 602, 414, 29, 50, 29, 603, 12, 604, 310, 603, 414,
+ 601, 602, 603, 603, 601, 602, 50, 29, 50, 29, 414, 605, 29, 29, 606, 29,
+ 29, 29, 29, 12, 414, 414, 606, 29, 51, 12, 12, 12, 12, 239, 0, 0,
+ 607, 12, 12, 12, 246, 12, 12, 12, 0, 0, 12, 0, 0, 232, 131, 0,
+ 0, 0, 12, 12, 0, 0, 0, 240, 0, 246, 12, 239, 608, 12, 12, 12,
+ 247, 247, 609, 12, 610, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
+ 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
+ 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
+ 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
+ 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
+ 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
+ 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
+ 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
+ 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
+ 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
+ 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
+ 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
+ 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0,
- 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0,
- 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271,
- 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
- 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26,
- 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280,
- 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
- 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290,
- 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297,
- 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0,
- 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0,
- 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
- 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301,
- 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
- 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26,
- 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2,
- 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26,
- 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53,
- 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324,
- 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328,
- 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163,
- 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26,
- 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175,
- 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343,
- 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26,
- 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31,
- 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361,
- 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290,
- 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367,
- 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26,
- 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
- 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378,
- 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280,
- 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
- 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26,
- 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
- 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
- 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
- 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26,
- 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
- 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26,
- 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26,
- 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424,
- 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430,
- 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26,
- 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436,
- 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447,
- 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26,
- 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457,
- 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26,
- 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467,
- 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50,
- 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476,
- 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26,
- 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485,
- 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491,
- 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26,
- 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26,
- 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26,
- 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509,
- 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26,
- 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26,
- 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26,
- 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26,
- 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26,
- 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26,
- 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26,
- 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543,
- 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26,
- 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26,
- 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555,
- 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558,
- 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564,
- 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575,
- 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581,
- 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
- 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26,
- 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26,
- 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26,
- 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
- 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26,
- 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
- 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601,
- 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26,
- 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609,
- 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610,
- 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612,
- 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617,
- 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26,
- 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621,
- 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626,
- 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627,
- 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630,
- 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636,
- 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26,
- 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0,
- 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0,
- 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0,
- 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
- 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26,
- 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171,
- 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666,
- 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26,
- 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0,
- 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26,
- 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680,
- 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26,
- 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26,
- 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0,
- 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26,
- 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0,
- 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376,
- 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26,
- 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26,
- 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26,
- 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
+ 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
+ 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
+ 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
+ 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
+ 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
+ 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 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, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
+ 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
+ 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
+ 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
+ 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
+ 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
+ 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
+ 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
+ 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
+ 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
+ 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
+ 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
+ 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
+ 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
+ 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
+ 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
+ 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
+ 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
+ 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
+ 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
+ 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
+ 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
+ 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
+ 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
+ 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
+ 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
+ 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
+ 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
+ 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
+ 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
+ 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
+ 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
+ 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
+ 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
+ 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
+ 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
+ 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
+ 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
+ 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
+ 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
+ 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
+ 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
+ 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
+ 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
+ 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
+ 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
+ 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
+ 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
+ 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
+ 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
+ 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
+ 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
+ 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
+ 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
+ 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
+ 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
+ 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
+ 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
+ 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
+ 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
+ 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
+ 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
+ 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
+ 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
+ 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
+ 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
+ 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
+ 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
+ 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
+ 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
+ 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
+ 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
+ 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
+ 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
+ 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
+ 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
+ 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
+ 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
+ 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
+ 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
+ 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
+ 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
+ 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
+ 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
+ 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
+ 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
+ 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
+ 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
+ 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
- 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
- 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
- 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
- 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
- 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
- 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
- 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
- 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
- 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
- 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
- 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
- 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
- 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
- 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
- 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
- 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
- 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
- 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
- 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
- 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 10,1425, 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, 1, 0,
- 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
- 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
- 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
- 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
- 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
- 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
- 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
- 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
- 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
- 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
- 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
- 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
- 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
- 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
- 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
- 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
- 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
- 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
- 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
- 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
- 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
- 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
- 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
- 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
- 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
- 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
- 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
- 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
- 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
- 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
- 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
- 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
- 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
- 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
- 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
- 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
- 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
- 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
- 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
- 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
- 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
- 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
- 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
- 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
- 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
- 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
- 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
- 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
- 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
- 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
- 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
- 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
- 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
- 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
- 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
- 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
- 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
- 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
- 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
- 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
- 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
- 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
- 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
- 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
- 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
- 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
- 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
- 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
- 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
- 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
- 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
- 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
- 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
- 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
- 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
- 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
- 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
- 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
- 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
- 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
- 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
- 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
- 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
- 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
- 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
- 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
- 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
- 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
- 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
- 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
- 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
- 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
- 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
- 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
- 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
- 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
- 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
- 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
- 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
- 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
- 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
- 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
- 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
- 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
- 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
- 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
- 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
- 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
- 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
- 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
- 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
- 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
- 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
- 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
- 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
- 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
- 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
- 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
- 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
- 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
- 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
- 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
- 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
- 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
- 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
- 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
- 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
- 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
- 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
- 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
- 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
+ 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
+ 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
+ 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
+ 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
+ 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
+ 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
+ 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
+ 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
+ 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
+ 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
+ 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
+ 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
+ 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
+ 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
+ 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
+ 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
+ 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
+ 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
+ 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
+ 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
+ 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
+ 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
+ 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
+ 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
+ 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
+ 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
+ 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
+ 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
+ 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
+ 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
+ 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
+ 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
+ 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
+ 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
+ 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[92] =
{
- 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
- 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
- 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
- -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
- 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
- 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
- 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
- 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
- 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
- -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
- 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
- -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
- -1, 0, 1, -1,
+ 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16,
+ 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914,
+ 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0,
+ 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8,
+ -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0,
+ 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0,
};
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[8984+(((_hb_ucd_u8[7960+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -5660,24 +4415,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9728+(((_hb_ucd_u8[9608+(((_hb_ucd_b4(9480+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9684+(((_hb_ucd_u8[9452+(((_hb_ucd_u8[9356+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11234+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10514+(((_hb_ucd_u8[10064+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11118+(((_hb_ucd_u16[4024+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10382+(((_hb_ucd_u8[9932+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[17136+(((_hb_ucd_u8[16754+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6728+(((_hb_ucd_u8[13944+(((_hb_ucd_u8[13562+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#else
static const uint8_t
-_hb_ucd_u8[13602] =
+_hb_ucd_u8[13370] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13,
@@ -5685,7 +4440,7 @@ _hb_ucd_u8[13602] =
7, 24, 21, 21, 21, 25, 26, 27, 21, 28, 29, 30, 31, 32, 33, 34,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35, 21, 36,
- 7, 7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 7, 7, 7, 7, 35, 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, 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,
@@ -5707,7 +4462,7 @@ _hb_ucd_u8[13602] =
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, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 38, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 37, 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, 21,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
@@ -5730,28 +4485,27 @@ _hb_ucd_u8[13602] =
34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119,
120,121,122,123,124,125,126,127, 34,128,129,111,130,131,132,133,
134,135,136,137,138,139,140,111,141,142,111,143,144,145,146,111,
- 147,148,149,150,151,152,111,111,153,154,155,156,111,157,111,158,
- 34, 34, 34, 34, 34, 34, 34, 34,159, 34, 34,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,160,
- 34, 34, 34, 34, 34, 34, 34, 34,161,111,111,111,111,111,111,111,
+ 147,148,149,150,151,152,153,111,154,155,156,157,111,158,159,160,
+ 34, 34, 34, 34, 34, 34, 34, 34,161, 34, 34,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,162,
+ 34, 34, 34, 34, 34, 34, 34, 34,163,111,111,111,111,111,111,111,
111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,
- 34, 34, 34, 34,162,163,164, 34,111,111,111,111,165,166,167,168,
+ 34, 34, 34, 34,164,165,166, 34,111,111,111,111,167,168,169,170,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,
111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119,
34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111, 34,169,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111,111,170, 67,
- 67, 67,171,172,173,130, 65,111,174,175,176,177,178,179,180,181,
- 67, 67, 67, 67,182,183,111,111,111,111,111,111,111,111,184,111,
- 185,111,186,111,111,187,111,111,111,111,111,111,111,111,111, 34,
- 34,188,189,111,111,111,111,111,130,190,191,111, 34,192,111,111,
- 67, 67,193, 67, 67,111, 67,194, 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67,195,111,111,111,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111, 34,171,111,111,111,111,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111,111,172, 67,
+ 67, 67,173,174,175,130, 65,111,176,177,178,179,180,181,182,183,
+ 67, 67, 67, 67,184,185,111,111,111,111,111,111,111,111,186,111,
+ 187,188,189,111,111,190,111,111,111,191,111,111,111,111,111, 34,
+ 34,192,193,111,111,111,111,111,130,194,195,111, 34,196,111,111,
+ 67, 67,197, 67, 67,111, 67,198, 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67,199,111,111,111,111,111,111,111,111,
34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
- 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,
- 196,111,185,185,111,111,111,111,111,111,111,111,111,111,111,111,
+ 200,111,188,188,111,111,111,111,111,111,111,111,111,111,111,111,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -5807,7 +4561,7 @@ _hb_ucd_u8[13602] =
36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43,
43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 85, 27, 27, 27, 84,
64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43,
- 43, 43, 77, 78, 78, 78, 81, 36, 86, 36, 36, 36, 36, 36, 36, 36,
+ 43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78,
43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78,
79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87,
27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77,
@@ -5947,7 +4701,7 @@ _hb_ucd_u8[13602] =
36, 64, 2, 36, 36, 36, 36, 36, 36, 82, 78, 43, 43, 43, 43, 77,
81, 36, 58, 2, 56, 43, 57, 79, 7, 7, 7, 7, 7, 58, 58, 2,
90, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 78, 79,
- 43, 78, 77, 43, 2, 2, 2, 43, 36, 36, 36, 36, 36, 36, 36, 64,
+ 43, 78, 77, 43, 2, 2, 2, 65, 36, 36, 36, 36, 36, 36, 36, 64,
77, 78, 78, 78, 78, 78, 78, 78, 36, 36, 36, 82, 78, 78, 81, 36,
36, 78, 78, 43, 43, 43, 43, 43, 36, 36, 82, 78, 43, 43, 43, 43,
78, 43, 77, 65, 36, 58, 2, 2, 7, 7, 7, 7, 7, 2, 2, 65,
@@ -5968,8 +4722,10 @@ _hb_ucd_u8[13602] =
43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43,
43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78,
43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97, 2, 2, 2, 2,
- 27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57, 2, 2, 2, 2, 2,
+ 43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78,
+ 77, 57, 2, 2, 2, 2, 2, 2, 27, 27, 84, 61, 61, 61, 53, 20,
+ 150, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21,
+ 65, 36, 36, 64, 43, 43, 43, 43, 43, 43, 57, 2, 2, 2, 2, 2,
43, 43, 43, 57, 2, 2, 61, 61, 40, 40, 89, 61, 61, 61, 61, 61,
7, 7, 7, 7, 7,167, 27, 27, 27, 87, 36, 36, 36, 36, 36, 36,
27, 27, 27, 30, 2, 2, 2, 2, 82, 78, 78, 78, 78, 78, 78, 78,
@@ -5992,485 +4748,469 @@ _hb_ucd_u8[13602] =
16, 16, 16, 16, 16, 39, 16, 16, 43, 43, 43, 68, 40, 40, 40, 40,
7, 7, 7, 7, 7, 7, 7, 71, 36, 36, 36, 36, 36, 36, 36, 43,
36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 7, 7,170,
- 16, 16, 43, 43, 43, 68, 40, 40, 27, 27, 27, 27, 27, 27,145, 27,
- 171, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145,
- 27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61, 61, 61, 25, 41, 41,
- 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
- 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
- 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
- 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
- 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
- 6, 6, 24, 24, 6, 24, 12, 12, 6, 5, 9, 21, 25, 9, 26, 12,
- 11, 11, 9, 6, 5, 21, 17, 17, 17, 26, 26, 23, 23, 12, 17, 12,
- 21, 12, 12, 21, 7, 21, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7,
- 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26,
- 26, 7, 21, 1, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
- 21, 6, 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, 15, 7,
- 12, 23, 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, 14, 14,
- 14, 7, 10, 21, 17, 21, 11, 12, 5, 6, 8, 8, 8, 24, 5, 24,
- 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20,
- 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6,
- 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
- 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 21, 22,
- 18, 17, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24,
- 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10,
- 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1,
- 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, 12, 17, 13, 15,
- 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0,
- 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26,
- 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 35,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 41, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0,
- 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13,
- 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20,
- 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
- 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0,
- 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0,
- 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0,
- 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0,
- 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0,
- 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0,
- 75, 0, 0, 76, 77, 0, 0, 78, 79, 0, 80, 62, 0, 81, 82, 0,
- 0, 83, 84, 85, 0, 0, 0, 86, 0, 87, 0, 0, 51, 88, 51, 0,
- 89, 0, 90, 0, 0, 0, 79, 0, 0, 0, 91, 92, 0, 93, 94, 95,
- 96, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 97, 98, 0, 0, 0,
- 0, 99,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,101, 0, 0,
- 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103,104, 0, 0,105,
- 0, 0, 0, 0, 0, 0,106, 0, 0, 0,100, 0, 0, 0, 0, 0,
- 107,108, 0, 0, 0, 0, 0, 0, 0,109, 0,110, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, 0, 9,
- 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, 0, 17,
- 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, 0, 24,
- 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31, 0, 0,
- 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0, 33, 36,
- 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0,
- 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44, 0, 0,
- 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 49, 0,
- 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0, 0, 0,
- 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58, 0, 0,
- 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63, 0, 0,
- 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70, 71, 72,
- 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79, 0, 0,
- 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82, 0, 83,
- 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78, 0, 0,
- 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0, 0, 0,
- 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0, 0, 0,
- 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94, 95, 0,
- 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,100, 93,
- 0, 0,101, 0, 0, 0, 84, 0, 0,102, 0, 0, 0,103,104, 0,
- 0,105,106, 0, 0, 0, 0, 0, 0,107, 0, 0,108, 0, 0, 0,
- 0,109, 33, 0,110,111,112, 35, 0, 0,113, 0, 0, 0,114, 0,
- 0, 0, 0, 0, 0,115, 0, 0,116, 0, 0, 0, 0,117, 88, 0,
- 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,118, 0, 0, 0, 0,119,
- 0, 0,120, 0, 0, 0, 0,118, 0, 0, 0, 0, 0,121, 0, 0,
- 0,122, 0, 0, 0,123, 0,124, 0, 0, 0, 0,125,126,127, 0,
- 128, 0,129, 0, 0, 0,130,131,132, 0, 0, 0, 35, 0, 0, 0,
- 133, 0, 0,134, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 1, 1,
- 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, 1, 11,
- 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0, 20, 21,
- 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 1, 1,
- 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0, 0, 38,
- 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45, 21, 45,
- 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1, 1, 49,
- 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1,
- 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55, 0, 0,
- 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0, 0, 0,
- 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0,
- 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0, 71, 72,
- 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0, 0, 0,
- 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0, 63, 0,
- 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 62, 0,
- 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87, 0, 55,
- 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 89,
- 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4, 90, 8,
- 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, 1, 94,
- 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0, 0, 0,
- 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102, 0, 0,
- 103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, 0, 0,
- 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,105,106,
- 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 84, 0,
- 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61, 0,110,
- 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0,111, 14, 52,112, 41,
- 0, 0, 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62,
- 0, 0, 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0,
- 78, 55, 0, 38, 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0,
- 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0,
- 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 8, 91,
+ 36, 36, 36, 36, 36, 75, 43, 43, 16, 16, 43, 43, 43, 68, 40, 40,
+ 27, 27, 27, 27, 27, 27,145, 27,171, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 61,
+ 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21,
+ 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
+ 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
+ 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
+ 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
+ 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
+ 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, 9, 6, 5, 21, 17, 17,
+ 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21, 7, 21, 1, 1,
+ 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1,
+ 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 24, 7, 7, 6,
+ 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 10, 7, 7, 10, 23, 7,
+ 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, 21, 26, 21, 15, 17, 7,
+ 29, 7, 7, 22, 18, 18, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12,
+ 5, 6, 8, 8, 8, 24, 5, 24, 9, 24, 29, 29, 29, 1, 20, 19,
+ 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22,
+ 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, 9, 26, 26, 9, 26, 5,
+ 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+ 18, 22, 5, 12, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, 17, 22,
+ 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21,
+ 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16,
+ 16, 22, 16, 16, 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15,
+ 21, 14, 7, 15, 12, 17, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0,
+ 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21,
+ 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 35, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0,
+ 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7,
+ 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19,
+ 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0,
+ 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0,
+ 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0,
+ 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55,
+ 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0,
+ 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0,
+ 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0,
+ 0, 0, 74, 0, 0, 0, 0, 0, 75, 76, 0, 77, 78, 0, 0, 79,
+ 80, 0, 81, 62, 0, 82, 83, 0, 0, 84, 85, 86, 0, 0, 0, 87,
+ 0, 88, 0, 0, 51, 89, 51, 0, 90, 0, 91, 0, 0, 0, 80, 0,
+ 0, 0, 92, 93, 0, 94, 95, 96, 97, 0, 0, 0, 0, 0, 51, 0,
+ 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0,
+ 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0, 0,
+ 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 0, 0,107,
+ 0, 0, 0, 0, 0, 0,108, 0,109, 0,102, 0, 0, 0, 0, 0,
+ 110,111, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 0,
+ 0,113, 0,114, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
+ 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13,
+ 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0,
+ 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27,
+ 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0,
+ 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0,
+ 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0,
+ 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0,
+ 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51,
+ 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56,
+ 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0,
+ 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0,
+ 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0,
+ 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81,
+ 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0,
+ 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0,
+ 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0,
+ 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0,
+ 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0,
+ 98, 0, 0, 0, 99, 0, 0, 0, 0,100,101, 93, 0, 0,102, 0,
+ 0, 0, 84, 0, 0,103, 0, 0, 0,104,105, 0, 0,106,107, 0,
+ 0, 0, 0, 0, 0,108, 0, 0,109, 0, 0, 0, 0,110, 33, 0,
+ 111,112,113, 35, 0, 0,114, 0, 0, 0,115, 0, 0, 0, 0, 0,
+ 0,116, 0, 0,117, 0, 0, 0, 0,118, 88, 0, 0, 0, 0, 0,
+ 57, 0, 0, 0, 0, 52,119, 0, 0, 0, 0,120, 0, 0,121, 0,
+ 0, 0, 0,119, 0, 0,122, 0, 0, 0, 0, 0, 0,123, 0, 0,
+ 0,124, 0, 0, 0,125, 0,126, 0, 0, 0, 0,127,128,129, 0,
+ 130, 0,131, 0, 0, 0,132,133,134, 0, 77, 0, 0, 0, 0, 0,
+ 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0,137, 0, 0,138, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6,
+ 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1,
+ 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26,
+ 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35,
+ 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0,
+ 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0,
+ 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 0,
+ 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21,
+ 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0,
+ 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0,
+ 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0,
+ 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77,
+ 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80,
+ 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0,
+ 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52,
+ 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0,
+ 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78,
+ 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1,
+ 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,
+ 100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0,
+ 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0,
+ 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0,
+ 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0,
+ 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0,
+ 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0,
+ 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, 62, 0,
+ 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0,
+ 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38,
+ 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0,
+ 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61,
+ 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, 8, 91,
0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, 0,117, 0,118,
119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 38, 50, 38, 58,
0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0,
- 0, 1, 4,122, 0, 0, 0, 1,123, 0, 0, 0, 0, 0,230,230,
- 230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202,
- 202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,
- 220,220,220,230,230,230,230,240,230,220,220,220,230,230,230,220,
- 220, 0,230,230,230,220,220,220,220,230,232,220,220,230,233,234,
- 234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,
- 220,230,230,230,222,220,230,230,220,220,230,222,228,230, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24,
- 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29,
- 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0,
- 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220,
- 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,
- 220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,
- 230,230,230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230,
- 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,
- 220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0,
- 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,
- 107,107,118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220,
- 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,
- 130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,
- 220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230,
- 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0,
- 0,220,230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0,
- 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,
- 230,230,230,230,232,228,228,220,218,230,233,220,230,220,230,230,
- 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,
- 218,228,232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,
- 230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,
- 220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9,
- 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0,
- 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,
- 216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, 17, 17,
- 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169,
- 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 0, 1, 0, 0, 0,123, 4,122, 0, 0, 0, 1,124, 0, 0, 0,
+ 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,220,220,
+ 220,220,220,202,202,220,220,220,220,202,202,220,220,220, 1, 1,
+ 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,220,220,
+ 230,230,230,220,220, 0,230,230,230,220,220,220,220,230,232,220,
+ 220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220,
+ 230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222,
+ 228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,
+ 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0,
+ 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,
+ 230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,
+ 220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,
+ 230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230,
+ 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,230,220,
+ 220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9,
+ 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84,
+ 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103,
+ 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,220,220,
+ 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0,
+ 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,
+ 230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9,
+ 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0,
+ 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0, 0, 0,
+ 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,
+ 214,220,202,230,230,230,230,230,232,228,228,220,218,230,233,220,
+ 230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230,
+ 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, 0, 0,
+ 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220,
+ 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,
+ 230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6,
+ 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,
+ 216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,230,230,
+ 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, 3, 3,
+ 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, 13, 3,
+ 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3,
+ 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3, 3, 3,
+ 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, 27, 28,
+ 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0,
+ 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0,
+ 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0,
+ 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24,
+ 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, 35, 19,
+ 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, 0, 1,
+ 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, 14, 0,
+ 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53,
+ 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, 19, 1,
+ 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, 0, 0,
+ 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0,
+ 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7,
+ 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0,
+ 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16,
+ 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9,
+ 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0,
+ 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28,
+ 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4,
+ 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21,
+ 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0,
+ 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1,
+ 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0,
+ 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21, 21, 21,
+ 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1,
+ 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 3, 3, 3, 3, 3, 3, 3, 15, 3, 16, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, 0, 3,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0,
- 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24,
- 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0,
- 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, 0, 1,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, 0, 0,
- 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0,
- 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, 0, 0,
- 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, 20, 20,
- 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, 20, 20,
- 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, 28, 29,
- 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
- 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, 0, 10,
- 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34,
- 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1,
- 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, 0, 1,
- 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,
- 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0,
- 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20,
- 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 11, 12, 12, 12,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 12, 21, 12, 12, 12, 12, 22,
- 23, 23, 23, 24, 12, 12, 12, 25, 26, 27, 12, 28, 29, 30, 31, 32,
- 33, 34, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35,
- 12, 36, 7, 7, 37, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 38, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 33, 34, 35, 35, 35, 35,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 2, 2, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 57, 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61,
- 56, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 71,
- 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 74, 74,
- 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89,
- 91, 92, 93, 94, 95, 95, 96, 97, 87, 98, 99,100,101,102,103,104,
- 105,105,105, 2,106,107,108,109,110,111,112,113,114,115,116, 87,
- 89,117,118,119,120,121,122,123,124,125,126, 87,127,128, 87,129,
- 130,131,132, 87,133,134,135,136,137,138, 87, 87,139,140,141,142,
- 87,143, 87,144,145,145,145,145,145,145,145,145,145,145,145, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87,146,147,147,147,147,147,147,147,147,147, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,148,148,148,148,
- 148, 87, 87, 87,149,149,149,149,150,151,152,152, 87, 87, 87, 87,
- 153,153,154,155,156,156,156,156,156,156,156,156,156,156,156,156,
- 156,156,156,156,156,156,156,156,156,156,157,157,157,157,156, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87,158,159,160,161,162,162,162, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,163,164, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87,165, 56, 56, 56,166,167, 51, 56, 56, 87, 56, 56, 56, 56,
- 56, 56, 56, 56,168,168,168,168,168,168, 87, 87, 87, 87, 87, 87,
- 87, 87, 2, 87,169, 87,170, 87, 87,171, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 33,172,172,173, 87, 87, 87, 87, 87, 56, 56, 56, 87,
- 89, 89, 87, 87, 56, 56, 56, 56,174, 87, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 56, 87,175,175, 0, 1, 2, 2, 0, 1, 2, 2,
- 2, 3, 4, 5, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3,
- 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
- 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11,
- 11, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18,
- 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21,
- 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27,
- 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 21, 21,
- 21, 21, 31, 21, 32, 32, 32, 32, 32, 33, 34, 32, 35, 35, 35, 35,
- 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37,
- 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39,
- 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41,
- 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43,
- 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46,
- 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50,
- 50, 50, 50, 51, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55,
- 55, 55, 55, 55, 56, 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61,
- 62, 62, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 55, 55, 55, 55, 55, 67, 67, 67, 67,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 18, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 17, 17, 18, 17, 19, 20, 21, 22, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 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, 25, 25, 26, 27, 28, 29, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 52, 53, 31, 31, 31, 31, 54, 55, 55, 56, 31,
+ 31, 31, 31, 31, 31, 31, 57, 58, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 59, 60, 31, 61, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 64, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 65, 66, 67, 31, 31,
+ 31, 31, 68, 31, 31, 31, 31, 31, 31, 31, 31, 69, 70, 71, 17, 17,
+ 72, 73, 31, 74, 75, 76, 77, 78, 79, 31, 80, 81, 17, 82, 17, 17,
+ 17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31,
+ 23, 83, 31, 31, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 84, 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3,
+ 4, 5, 6, 7, 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6,
+ 7, 8, 9, 10, 11, 11, 12, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 19, 27, 28, 29, 30, 30, 31, 31, 32, 32,
+ 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 40, 41, 41,
+ 42, 42, 42, 43, 44, 44, 45, 46, 47, 47, 47, 47, 48, 48, 48, 48,
+ 48, 48, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53,
+ 54, 55, 56, 56, 57, 58, 59, 51, 60, 61, 62, 63, 64, 65, 66, 7,
+ 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 7, 4, 4, 4, 4,
+ 77, 77, 77, 77, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 85, 85, 85, 85, 0, 0, 0, 0, 86, 87, 88, 88,
+ 89, 90, 48, 91, 0, 0, 92, 92, 92, 92, 92, 93, 94, 95, 96, 97,
+ 98, 47, 99,100,101,102, 0,103,104,105, 0, 0, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0,106,106,106,106,
+ 106,106,106,106,106,106,106,107,108,108,108,108,108, 11,109,110,
+ 111, 4,112, 4,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126, 50,127, 47, 47, 47, 47, 47, 47, 47, 47,128,128,128,128,
+ 128,128,128,128,128,128,128,128, 92, 92, 92, 92, 92, 92, 92, 92,
+ 129,130, 19, 19, 19, 19, 19, 19,131, 19, 19, 19,132,133, 19,134,
+ 135,136,137,101,138,138,138,138, 0, 77,139,140,128,128,141,142,
+ 143,144,145,146,147,148,149,150,151,152,153,153,154,154,154,154,
+ 154,154, 4, 4,155,156,157,158,159,160,161,162,163,164,165,166,
+ 167,168,169,169,170,170,171,171,172,172,128,128, 19, 19,173,174,
+ 175,176,177,178,179,179,180,181,182,183,184,185,186,186,187,188,
+ 189,190,128,128,191,191,192,192,128,128,193,193,194,195,196,196,
+ 197,197,128,128,198,198,199,199,200,200,201,201,202,203,204,205,
+ 28, 28,128,128,206,207,208,208,209,210,211,211,128,128,212,212,
+ 213,213,214, 34,215,215,215,215,215,215,215,215,215,215,215,215,
+ 215,215,128,128,128,128,128,128,128,128,216,216,217,217,217,217,
+ 217,217,217,217,217,217,128,128,128,128,128,128,218,218,218,218,
+ 218,218,218,218,218,218,128,128,128,128,128,128,110,110,110,110,
+ 110,110,110,110,110,219,220,221,222,222,222,222,223,223,223,223,
+ 224,224,224,225,226,226,226,226,226,226,226,226,226,226,226,226,
+ 227,227,227,227,227,227,227,227,226,226,128,128,128,128,128,128,
+ 128,128,104,104,228,229,229,229,230,231,232,232,232,232,232,232,
+ 128,128,128,128,233,233,234, 0,128,128,128,128,128,128,128,128,
+ 7,235, 0, 0, 0, 0, 0, 0, 0,236,237, 0, 77, 77, 0, 0,
+ 0, 0,128,128,238,238,238,238,238,238,238,238,238,238,238,238,
+ 128,128,128,128,128,128,128,128, 4, 4,128,128,239, 11, 11, 11,
+ 240,240,128,128,128,128,241,242,128,128,128,128,128,128,243,243,
+ 128,128,128,128,128,128,128,128,128,128, 48, 48,244,244,244,244,
+ 245,245,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19,
+ 128,128,128,128,246, 0,128,128, 0, 0, 0, 0, 92, 92,128,128,
+ 128,128,128,128, 0, 0,128,128, 7, 7, 7, 7, 0, 0, 0, 0,
+ 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4,
+ 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9,
+ 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 14, 13, 13, 13,
+ 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18,
+ 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21,
+ 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 31, 21, 32, 32, 32, 32,
+ 32, 33, 34, 32, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+ 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41,
+ 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44,
+ 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49,
+ 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53,
+ 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57,
+ 57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64,
+ 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 67, 67, 67, 67,
67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 8, 8, 8, 8, 8, 72, 72, 72, 72,
- 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
- 75, 76, 76, 76, 13, 50, 50, 50, 73, 77, 78, 79, 4, 4, 80, 4,
- 4, 81, 82, 83, 4, 4, 4, 84, 8, 8, 8, 8, 11, 11, 11, 11,
+ 71, 71, 71, 71, 71, 71, 71, 8, 72, 72, 72, 72, 73, 73, 73, 73,
+ 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50,
+ 73, 77, 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84,
11, 11, 11, 11, 85, 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0,
0, 8, 8, 8, 0, 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 90,
90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92,
- 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 53, 53,
- 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 94, 94, 94, 94,
94, 94, 94, 0, 95, 0, 96, 97, 98, 99, 99, 99, 99,100,101,102,
- 102,102,102,103,104,104,104,105, 52, 52, 52, 52, 52, 0,104,104,
- 0, 0, 0,102, 52, 52, 0, 0, 0, 0, 52,106, 0, 0, 0, 0,
- 0,102,102,107,102,102,102,102,102,108, 0, 0, 94, 94, 94, 94,
- 0, 0, 0, 0,109,109,109,109,109,109,109,109,109,109,109,109,
- 109,110,110,110,111,111,111,111,111,111,111,111,111,111,111,111,
- 13, 13, 13, 13, 13, 13,112,112,112,112,112,112, 0, 0,113, 4,
- 4, 4, 4, 4,114, 4, 4, 4, 4, 4, 4, 4,115,115,115, 0,
- 116,116,116,116,117,117,117,117,117,117, 32, 32,118,118,119,120,
- 120,120, 52, 52,121,121,121,121,122,121, 49, 49,123,123,123,123,
- 123,123, 49, 49,124,124,124,124,124,124,125,125, 53, 53, 53, 4,
- 4,126,127, 54, 54, 54, 54, 54,125,125,125,125,128,128,128,128,
- 128,128,128,128, 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21,130, 21, 21, 21, 21, 8, 0,131, 0,
- 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 21,132, 0, 0, 1, 2,
- 1, 2,133,101,102,134, 52, 52, 52, 52, 0, 0,135,135,135,135,
- 135,135,135,135, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 11, 11,
- 11, 0, 0,136,137,137,138,138,138,138,139, 0,140,140,140,141,
- 141,142,142,142,143,143,144,144,144,144,144,144,145,145,145,145,
- 145,146,146,146,147,147,147,148,148,148,148,148,149,149,149,150,
- 150,150,150,151,151,151,151,151,151,151,151,151,152,152,152,152,
- 152,152,152,152,153,153,153,153,154,154,155,155,156,156,156,156,
- 156,156,157,157,158,158,159,159,159,159,159,159,160,160,161,161,
- 161,161,161,161,162,162,162,162,162,162,163,163,164,164,164,164,
- 165,165,165,165,166,166,166,166,167,167,168,168,169,169,169,169,
- 169,169,169,169,170,170,170,170,170,170,170,170,171,171,171,171,
- 171,171,171,171,172,172,172,172,172,172,172,172,173,173,173,173,
- 173,173,173,173,174,174,174,175,175,175,175,176,176,176,176,177,
- 177,177,178,178,179,179,179,179,179,179,179,179,180,180,180,180,
- 180,181,181,181,182,182,182,182,182,183,183,183,184,184,184,184,
- 184,184,185, 43,186,186,186,186,186,186,186,186,187,187,187,188,
- 188,188,188,188,189,189,189,190,189,189,189,189,191,191,191,191,
- 191,191,191,191,192,192,192,192,192,192,192,192,193,193,193,193,
- 193,193,193,193,194,194,194,194,194,194, 66, 66,195,195,195,195,
- 195,195,195,195,196,196,196,196,196,196,196,196,197,197,197,197,
- 197,197,197,197,198,198,198,198,198,198,198,198,199,199,199,199,
- 199,199,199,199,200,200,200,200,200,200,200,200,201,201,201,201,
- 201,202,202,202,202,202,202, 55,203,203,203,203,204,204,204,204,
- 204,204,204,205,205,205,205,205,205,205,205,205,206,206,206,206,
- 206,206,207,207,207,207,207,207,207,207,207,207,208,208,208,208,
- 208,208,208,208,110,110,110,110, 39, 39, 39, 39,209,209,209,209,
- 209,209,209,209,210,210,210,210,210,210,210,210,211,211,211,211,
- 211,211,211,211,212,212,212,212,212,212,212,212,112,112,112,112,
- 112,112,112,112,112,112,112,112,213,213,213,214,214,214,214,214,
- 214,215,215,215,216,216,216,216,216,216,216,216,217,217,217,217,
- 217,217,217,217,218,218,218,218,218,218,218,218,218,218,218,218,
- 218,218,219, 94,220,220,220,220,220,220,220,220,221,221,221,221,
- 221,221,221,221,102,102,102,102,102,102,102,102,222, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,102,102,
- 102, 99,223,224,224,224,224,224,224,224,224,224,225,225,225,225,
- 225,225,225,225,225,225, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
- 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,226,227,228, 0,229, 0,
- 0, 0, 0, 0,230,230,230,230,230,230,230,230, 91, 91, 91, 91,
- 91, 91, 91, 91,231,231,231,231,231,231,231,231,232,232,232,232,
- 233,233,233,233,234,234,234,234,234,234,234,234,235,235,235,235,
- 235,235,235,235,236, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
- 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0,
- 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0,
- 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8,
- 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14,
- 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19,
- 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24, 7,
- 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27,
- 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
- 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33,
- 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40,
- 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44,
- 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 48, 48, 48, 48,
- 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53,
- 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57,
- 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62,
- 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0, 66, 66, 66, 66,
- 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71,
- 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
- 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79,
- 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7, 83, 7, 84, 85,
- 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89, 90, 87, 91, 2,
- 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86, 1, 0, 0, 94,
- 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4, 97, 97, 97, 97,
- 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100,
- 0,101, 0, 0,102,100,103,104, 0, 0,100, 0,105,106,106,106,
- 106,106,106,106,106,106,107,105,108,109,109,109,109,109,109,109,
- 109,109,110,108,111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,
- 109,109,109,110,109,109, 0, 0,114,114,114,114,115,115,115,115,
- 116,116,116,116,117,117,117,117, 96, 2, 2, 2, 2, 2, 94, 2,
- 118,118,118,118,119,119,119,119,120,120,120,120,121,121,121,121,
- 121,121,121,122,123,123,123,123,124,124,124,124,124,124,124,125,
- 126,126,126,126,127,127,127,127,128,128,128,128, 2, 2, 3, 2,
- 2,129,130, 0,131,131,131,131,132, 17, 17, 18, 20, 20, 20,133,
- 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109,109,109,109,136,
- 137,137,137,137, 0, 0, 0,138,139,139,139,139,140,140,140,140,
- 84, 0, 0, 0,141,141,141,141,142,142,142,142,143,143,143,143,
- 144,144,144,144,145,145,145,145,146,146,146,146,147,147,147,147,
- 148,148,148,148,149,149,149,149,150,150,150,150,151,151,151,151,
- 152,152,152,152,153,153,153,153,154,154,154,154,155,155,155,155,
- 156,156,156,156,157,157,157,157,158,158,158,158,159,159,159,159,
- 160,160,160,160,161,161,161,161,162,162,162,162,163,163,163,163,
- 164,164,164,164,165,165,165,165,166,166,166,166,167,167,167,167,
- 168,168,168,168,169,169,169,169,170,170,170,170,171,171,171,171,
- 172,172,172,172,173,173,173,173,174,174,174,174,175,175,175,175,
- 176,176,176,176,177,177,177,177,178,178,178,178,179,179,179,179,
- 180,180,180,180,181,181,181,181,182,182,182,182,183,183,183,183,
- 184,184,184,184,185,185,185,185,186, 45, 45, 45,187,187,187,187,
- 188,188,188,188,189,189,189,189,190,190,190,190,190,190,191,190,
- 192,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,
- 196,196,196,196,197,197,197,197,198,198,198,198,199,199,199,199,
- 200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203,
- 204,204,204,204,205,205,205,205,206,206,206,206,207,207,207,207,
- 208,208,208,208,209,209,209,209,210,210,210,210,211,211,211,211,
- 212,212,212,212,213,213,213,213,214,214,214,214,215,215,215,215,
- 216,216,216,216,217,217,217,217,218,218,218,218,219,219,219,219,
- 220,221,221,221,222,222,222,222,221,221,221,221,223,106,106,106,
- 106,109,109,109,224,224,224,224,225,225,225,225, 0,226, 86, 0,
- 0, 0,226, 7, 82,138, 7, 0, 0, 0,227, 86,228,228,228,228,
- 229,229,229,229,230,230,230,230,231,231,231,231,232,232,232,232,
- 233,233,233,233,234, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0,
- 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9,
- 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55,
- 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4,
- 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3,
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3,
- 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64,
- 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7,
- 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5,
- 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22,
- 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36,
- 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25,
- 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8,
- 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29,
- 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0,
- 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0,
- 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0,
- 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52,
- 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62,
- 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73,
- 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
- 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9,
- 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9,
- 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27,
- 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13,
- 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15,
- 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0,
- 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79,
- 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69,
- 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0,
- 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19,
- 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0,
- 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49,
- 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42,
- 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59,
- 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,
- 106,106,106,106,104,104,104,104,161,161,161,161,110,110,110,110,
- 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,
- 128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98,
- 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,
- 112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,
- 122,122,122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,
- 156,156,156,156,147,147,147,147,148,148,148,148,158,158,158,158,
- 153,153,153,153,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,
- 101,101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100,
- 100, 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109,
- 107,107,107,107,107,107,107, 1,137,137,137,137,124,124,124,124,
- 123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126,
- 142,142,142,142,125,125,125,125,154,154,154,154,150,150,150,150,
- 141,141,141,141,140,140,140,140,121,121,121,121,133,133,133,133,
- 134,134,134,134,138,138,138,138,143,143,143,143,145,145,145,145,
- 63, 63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,
- 115,115,115,115,159,159,159,159,103,103,103,103,119,119,119,119,
- 146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,
- 136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,105,105,
- 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151,151,151,151,
- 160,160,160,160,152,152,152,152,113,113,113,113,132,132,132,132,
- 15, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9,
- 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 102,102,102,103,104,104,104,105, 52, 0,104,104, 0, 0, 0,102,
+ 52, 52, 0, 0, 0, 0, 52,106, 0,102,102,107,102,102,102,102,
+ 102,108, 0, 0,109,109,109,109,109,110,110,110,111,111,111,111,
+ 13, 13,112,112,112,112,112,112, 0, 0,113, 4,114, 4, 4, 4,
+ 115,115,115, 0,116,116,116,116,117,117,117,117,117,117, 32, 32,
+ 118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, 49, 49,
+ 123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,125,125,
+ 53, 53, 53, 4, 4,126,127, 54,125,125,125,125,128,128,128,128,
+ 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130, 8, 0,131, 0,
+ 0, 0, 0, 21, 21, 21, 21,132, 0, 0, 1, 2, 1, 2,133,101,
+ 102,134, 52, 52,135,135,135,135, 11, 0, 11, 11, 11, 0, 0,136,
+ 137,137,138,138,138,138,139, 0,140,140,140,141,141,142,142,142,
+ 143,143,144,144,144,144,144,144,145,145,145,145,145,146,146,146,
+ 147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,151,
+ 151,151,151,151,152,152,152,152,153,153,153,153,154,154,155,155,
+ 156,156,156,156,156,156,157,157,158,158,159,159,159,159,159,159,
+ 160,160,161,161,161,161,161,161,162,162,162,162,162,162,163,163,
+ 164,164,164,164,165,165,165,165,166,166,166,166,167,167,168,168,
+ 169,169,169,169,170,170,170,170,171,171,171,171,172,172,172,172,
+ 173,173,173,173,173,173,173,174,175,175,175,176,176,176,176,177,
+ 177,177,177,178,178,178,179,179,180,180,180,180,181,181,181,181,
+ 181,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185,
+ 185,185,186, 43,187,187,187,187,188,188,188,189,189,189,189,189,
+ 190,190,190,191,190,190,190,190,192,192,192,192,193,193,193,193,
+ 194,194,194,194,195,195,195,195,195,195, 66, 66,196,196,196,196,
+ 197,197,197,197,198,198,198,198,199,199,199,199,200,200,200,200,
+ 201,201,201,201,202,202,202,202,202,203,203,203,203,203,203, 55,
+ 204,204,204,204,205,205,205,205,205,205,205,206,206,206,206,206,
+ 207,207,207,207,207,207,208,208,208,208,208,208,209,209,209,209,
+ 210,210,210,210,110,110,110,110,211,211,211,211,212,212,212,212,
+ 213,213,213,213,214,214,214,214,215,215,215,216,216,216,216,216,
+ 216,217,217,217,218,218,218,218,219,219,219,219,220,220,220,220,
+ 220,220,221, 94,222,222,222,222,223,223,223,223,224, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99,102,225, 99,226,102,227,227,227,227,227,
+ 228,228,228,228,228,228, 0, 0, 8, 0, 0, 0, 0, 0,229,230,
+ 231, 0,232, 0,233,233,233,233, 91, 91, 91, 13,234,234,234,234,
+ 235,235,235,235,236,236,236,236,237,237,237,237,238,238,238,238,
+ 239,239,239,239,240, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2,
+ 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2,
+ 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10,
+ 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14,
+ 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19,
+ 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20,
+ 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21,
+ 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30,
+ 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33,
+ 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47,
+ 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52,
+ 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56,
+ 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60,
+ 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0,
+ 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71,
+ 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74,
+ 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78,
+ 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7,
+ 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89,
+ 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86,
+ 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4,
+ 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,
+ 100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0,100, 0,
+ 105,106,106,106,106,106,106,106,106,106,107,105,108,109,109,109,
+ 109,109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55,
+ 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114,114,114,
+ 115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, 2, 2,
+ 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120,120,120,
+ 121,121,121,121,121,121,121,122,123,123,123,123,124,124,124,124,
+ 124,124,124,125,126,126,126,126,127,127,127,127,128,128,128,128,
+ 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, 17, 18,
+ 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109,
+ 109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139,139,139,
+ 140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142,142,142,
+ 143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146,
+ 147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150,
+ 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,
+ 155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158,
+ 159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162,
+ 163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166,
+ 167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,
+ 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174,
+ 174,174,174,175,176,176,176,176,177,177,177,177,178,178,178,178,
+ 179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,
+ 183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,
+ 187, 45, 45, 45,188,188,188,188,189,189,189,189,190,190,190,190,
+ 191,191,191,191,191,191,192,191,193,193,193,193,194,194,194,194,
+ 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
+ 199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,
+ 203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,
+ 207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,
+ 211,211,211,211,212,212,212,212,213,213,213,213,214,214,214,214,
+ 215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,
+ 219,219,219,219,220,220,220,220,221,221,221,221,222,223,223,223,
+ 224,224,224,224,223,223,223,223,225,106,106,106,226,106,106,106,
+ 106,227,109,109,228,228,228,228,229,229,229,229, 0,230, 86, 0,
+ 0, 0,230, 7, 82,138, 7, 0, 0, 0,231, 86,232,232,232,232,
+ 233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,
+ 237,237,237,237,238,238,238,238,239, 0, 0, 0, 0, 0, 0, 0,
+ 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0,
+ 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9,
+ 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55,
+ 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4,
+ 4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3,
+ 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1,
+ 1, 1, 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38,
+ 64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3,
+ 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7,
+ 5, 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21,
+ 22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20,
+ 36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18,
+ 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33,
+ 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30,
+ 29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35,
+ 35, 35, 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44,
+ 44, 0, 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31,
+ 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48,
+ 52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91,
+ 62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70,
+ 73, 73, 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6,
+ 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19,
+ 19, 19, 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19,
+ 27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,
+ 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12,
+ 0, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12,
+ 12, 12, 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77,
+ 79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75,
+ 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84,
+ 84, 84, 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87,
+ 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4,
+ 3, 3, 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0,
+ 49, 49, 49, 49, 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67,
+ 42, 42, 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53,
+ 59, 59, 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,
+ 135,135,135,135,106,106,106,106,104,104,104,104,161,161,161,161,
+ 110,110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,
+ 116,116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72,
+ 98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,
+ 117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83,
+ 82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130,130,130,130,
+ 144,144,144,144,156,156,156,156,156, 3, 3, 3,147,147,147,147,
+ 148,148,148,148,158,158,158,158,153,153,153,153,149,149,149,149,
+ 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, 96, 96,
+ 111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108,108,108,
+ 129,129,129,129,109,109,109,109,107,107,107,107,107,107,107, 1,
+ 137,137,137,137,124,124,124,124,123,123,123,123,114,114,114,114,
+ 102,102,102,102,126,126,126,126,142,142,142,142,125,125,125,125,
+ 154,154,154,154,150,150,150,150,141,141,141,141,140,140,140,140,
+ 121,121,121,121,133,133,133,133,134,134,134,134,138,138,138,138,
+ 143,143,143,143,145,145,145,145,163,163,163,163, 63, 63, 63, 63,
+ 157,157,157,157, 80, 80, 80, 80,127,127,127,127,115,115,115,115,
+ 159,159,159,159,103,103,103,103,119,119,119,119,146,146,146,146,
+ 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136,
+ 17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,
+ 105,105,105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,
+ 151,151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,
+ 113,113,113,113,132,132,132,132, 15, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9,
+ 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9,
- 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -6479,60 +5219,60 @@ _hb_ucd_u8[13602] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30,
- 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37,
- 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42,
+ 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0,
+ 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34,
+ 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45,
+ 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51,
+ 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0,
+ 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0,
+ 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59,
+ 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47,
- 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0,
- 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0,
- 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0,
- 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0,
+ 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,
+ 111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,
+ 120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 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,100,
- 101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0,
- 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,
- 115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,
+ 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,
+ 150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126,
- 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
- 142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,
- 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0,
- 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0,
+ 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169,
+ 170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,177,178,
+ 179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,
+ 195,196,197,198,199,200,201,202,203,204,205,206, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0,
- 0, 0,173,174,175,176,177,178,179,180,181,182,183,184,185,186,
- 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,
- 203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
- 3, 4,
+ 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[4888] =
+_hb_ucd_u16[4920] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -6599,39 +5339,41 @@ _hb_ucd_u16[4888] =
359, 47, 47, 360, 145, 66, 47, 361, 47, 362, 145, 145, 363, 47, 364, 66,
47, 47, 47, 365, 47, 366, 47, 366, 47, 365, 144, 145, 145, 145, 145, 145,
9, 9, 9, 9, 11, 11, 11, 367, 47, 47, 368, 160, 160, 160, 160, 160,
- 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 47,
+ 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 143,
47, 362, 370, 47, 60, 371, 66, 47, 372, 66, 66, 47, 373, 145, 47, 47,
374, 47, 47, 360, 375, 376, 377, 378, 180, 47, 47, 379, 380, 47, 47, 160,
97, 47, 381, 382, 383, 47, 47, 384, 180, 47, 47, 385, 386, 387, 388, 145,
- 47, 47, 389, 390, 32, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160,
+ 47, 47, 389, 390, 359, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160,
92, 47, 47, 113, 392, 393, 394, 32, 47, 47, 47, 395, 396, 397, 47, 47,
47, 47, 47, 398, 399, 160, 160, 160, 47, 47, 400, 401, 402, 403, 32, 32,
47, 47, 47, 404, 405, 160, 66, 66, 47, 47, 406, 407, 160, 160, 160, 160,
47, 143, 408, 409, 47, 47, 47, 47, 47, 47, 389, 410, 66, 66, 66, 66,
9, 9, 9, 9, 11, 11, 128, 411, 47, 47, 47, 412, 413, 160, 160, 160,
47, 47, 47, 47, 47, 414, 415, 416, 417, 47, 47, 418, 419, 420, 47, 47,
- 421, 422, 66, 47, 47, 47, 47, 47, 47, 47, 400, 423, 424, 128, 145, 425,
- 47, 156, 426, 427, 32, 32, 32, 32, 47, 47, 47, 359, 428, 160, 47, 47,
- 429, 430, 160, 160, 160, 160, 160, 160, 47, 47, 47, 47, 47, 47, 47, 431,
- 47, 47, 47, 47, 145, 432, 433, 434, 219, 219, 219, 219, 219, 219, 219, 66,
- 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 208, 208, 208, 208,
- 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 435,
- 47, 47, 47, 436, 437, 438, 439, 47, 9, 9, 9, 9, 9, 9, 11, 11,
- 145, 440, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 441, 416, 416,
- 442, 443, 27, 27, 27, 27, 444, 416, 47, 445, 208, 208, 208, 208, 208, 208,
- 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 446, 447,
- 448, 146, 449, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 146, 146, 146,
- 9, 451, 11, 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11,
- 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 452, 453, 11,
- 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 196, 9, 457, 458, 459, 460,
- 11, 461, 9, 462, 463, 464, 465, 11, 466, 9, 467, 11, 468, 160, 160, 160,
- 32, 32, 32, 469, 32, 32, 470, 471, 472, 473, 32, 32, 32, 32, 32, 32,
- 474, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 32, 32, 32, 32, 32,
- 47, 47, 47, 475, 476, 146, 146, 146, 47, 47, 477, 32, 47, 47, 478, 479,
- 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 454, 11, 480, 305, 66, 66,
- 145, 145, 481, 482, 145, 145, 145, 145, 145, 145, 483, 145, 145, 145, 145, 145,
- 47, 47, 47, 47, 47, 47, 47, 226, 484, 146, 146, 146, 146, 146, 146, 146,
- 146, 146, 146, 146, 146, 146, 146, 485, 146, 146, 146, 146, 146, 146, 146, 160,
+ 421, 422, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 66, 66,
+ 47, 47, 400, 423, 424, 128, 145, 425, 47, 156, 426, 427, 32, 32, 32, 32,
+ 47, 47, 47, 359, 428, 160, 47, 47, 429, 430, 160, 160, 160, 160, 160, 160,
+ 47, 47, 47, 47, 47, 47, 47, 431, 432, 47, 47, 433, 434, 160, 160, 160,
+ 47, 47, 47, 47, 145, 435, 436, 437, 219, 219, 219, 219, 219, 219, 219, 66,
+ 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 438, 32, 32, 32,
+ 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 439,
+ 47, 47, 47, 440, 441, 442, 443, 47, 9, 9, 9, 9, 9, 9, 11, 11,
+ 145, 444, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 445, 416, 416,
+ 446, 447, 27, 27, 27, 27, 448, 416, 47, 449, 208, 208, 208, 208, 208, 208,
+ 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 451,
+ 452, 146, 453, 146, 146, 146, 146, 146, 146, 146, 146, 146, 454, 146, 146, 146,
+ 9, 455, 11, 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11,
+ 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 456, 457, 11,
+ 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 196, 9, 461, 462, 463, 464,
+ 11, 465, 9, 466, 467, 468, 469, 11, 470, 9, 471, 11, 472, 160, 160, 160,
+ 32, 32, 32, 473, 32, 32, 474, 475, 476, 477, 32, 32, 32, 32, 32, 32,
+ 478, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 27, 27, 27, 27, 27,
+ 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 479, 480, 146, 146, 146,
+ 47, 47, 481, 32, 47, 47, 482, 483, 47, 47, 47, 47, 47, 47, 484, 160,
+ 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 458, 11, 485, 305, 66, 66,
+ 145, 145, 486, 487, 145, 145, 145, 145, 145, 145, 488, 145, 145, 145, 145, 145,
+ 47, 47, 47, 47, 47, 47, 47, 226, 489, 146, 146, 146, 146, 146, 146, 146,
+ 146, 146, 146, 146, 146, 146, 146, 490, 146, 146, 146, 146, 146, 146, 146, 160,
208, 208, 208, 208, 208, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
@@ -6842,32 +5584,25 @@ _hb_ucd_u16[4888] =
817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[92] =
{
- 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
- 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
- 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
- -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
- 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
- 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
- 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
- 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
- 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
- -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
- 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
- -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
- -1, 0, 1, -1,
+ 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16,
+ 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914,
+ 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0,
+ 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8,
+ -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0,
+ 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0,
};
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114112u?_hb_ucd_u8[5056+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114112u?_hb_ucd_u8[5080+(((_hb_ucd_u8[1152+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[6970+(((_hb_ucd_u8[6426+(((_hb_ucd_u8[5982+(((_hb_ucd_u8[5646+(((_hb_ucd_u8[5400+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[7038+(((_hb_ucd_u8[6482+(((_hb_ucd_u8[6022+(((_hb_ucd_u8[5670+(((_hb_ucd_u8[5424+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -6877,17 +5612,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7714+(((_hb_ucd_u8[7594+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7930+(((_hb_ucd_u8[7698+(((_hb_ucd_u8[7602+(((_hb_ucd_b4(7538+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918016u?_hb_ucd_u8[11480+(((_hb_ucd_u8[10532+(((_hb_ucd_u8[9124+(((_hb_ucd_u8[8500+(((_hb_ucd_u8[8050+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+ return u<918016u?_hb_ucd_u8[11228+(((_hb_ucd_u8[10264+(((_hb_ucd_u8[9276+(((_hb_ucd_u8[8596+(((_hb_ucd_u8[8292+(((_hb_ucd_u8[8178+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12802+(((_hb_ucd_u8[12420+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12570+(((_hb_ucd_u8[12188+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#endif
diff --git a/src/hb-ucd.cc b/src/hb-ucd.cc
index baea224a2..4c8b1ee5e 100644
--- a/src/hb-ucd.cc
+++ b/src/hb-ucd.cc
@@ -129,12 +129,16 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
void *user_data HB_UNUSED)
{
+ // Hangul is handled algorithmically.
if (_hb_ucd_compose_hangul (a, b, ab)) return true;
hb_codepoint_t u = 0;
if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
{
+ /* If "a" is small enough and "b" is in the U+0300 range,
+ * the composition data is encoded in a 32bit array sorted
+ * by "a,b" pair. */
uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
const uint32_t *v = hb_bsearch (k,
_hb_ucd_dm2_u32_map,
@@ -146,6 +150,8 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
else
{
+ /* Otherwise it is stored in a 64bit array sorted by
+ * "a,b" pair. */
uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
const uint64_t *v = hb_bsearch (k,
_hb_ucd_dm2_u64_map,
@@ -170,15 +176,22 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
unsigned i = _hb_ucd_dm (ab);
+ /* If no data, there's no decomposition. */
if (likely (!i)) return false;
i--;
+ /* Check if it's a single-character decomposition. */
if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map))
{
+ /* Single-character decompositions currently are only in plane 0 or plane 2. */
if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map))
+ {
+ /* Plane 0. */
*a = _hb_ucd_dm1_p0_map[i];
+ }
else
{
+ /* Plane 2. */
i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map);
*a = 0x20000 | _hb_ucd_dm1_p2_map[i];
}
@@ -187,8 +200,10 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map);
+ /* Otherwise they are encoded either in a 32bit array or a 64bit array. */
if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map))
{
+ /* 32bit array. */
uint32_t v = _hb_ucd_dm2_u32_map[i];
*a = HB_CODEPOINT_DECODE3_11_7_14_1 (v);
*b = HB_CODEPOINT_DECODE3_11_7_14_2 (v);
@@ -196,6 +211,7 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map);
+ /* 64bit array. */
uint64_t v = _hb_ucd_dm2_u64_map[i];
*a = HB_CODEPOINT_DECODE3_1 (v);
*b = HB_CODEPOINT_DECODE3_2 (v);
diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh
index c21637920..13b1c4b1d 100644
--- a/src/hb-unicode-emoji-table.hh
+++ b/src/hb-unicode-emoji-table.hh
@@ -6,16 +6,16 @@
*
* on file with this header:
*
- * # emoji-data-14.0.0.txt
- * # Date: 2021-08-26, 17:22:22 GMT
- * # © 2021 Unicode®, Inc.
+ * # emoji-data.txt
+ * # Date: 2022-08-02, 00:26:10 GMT
+ * # © 2022 Unicode®, Inc.
* # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
- * # For terms of use, see http://www.unicode.org/terms_of_use.html
+ * # For terms of use, see https://www.unicode.org/terms_of_use.html
* #
* # Emoji Data for UTS #51
- * # Used with Emoji Version 14.0 and subsequent minor revisions (if any)
+ * # Used with Emoji Version 15.0 and subsequent minor revisions (if any)
* #
- * # For documentation and usage, see http://www.unicode.org/reports/tr51
+ * # For documentation and usage, see https://www.unicode.org/reports/tr51
*/
#ifndef HB_UNICODE_EMOJI_TABLE_HH
@@ -24,42 +24,37 @@
#include "hb-unicode.hh"
static const uint8_t
-_hb_emoji_u8[544] =
+_hb_emoji_u8[464] =
{
16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
- 0, 0, 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,
- 2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 7, 8,
- 0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 14, 13, 15, 16, 17, 0,
- 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0,
- 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0,
- 13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
- 13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13, 0, 33, 0, 34,
- 35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0,
- 0, 0, 0, 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
- 0,128, 0, 0, 0,254, 15, 7, 4, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, 0, 0, 0,120,
- 191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
- 63, 0,255,255,255,255,255,255, 63,255, 87, 32, 2, 1, 24, 0,
- 144, 80,184, 0,248, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128,
- 0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0,
- 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32,
- 0, 0,128, 2, 0, 0, 0, 0, 0,224, 0, 0, 0,128, 0, 0,
- 0, 0, 0, 0, 0,240, 3,192, 0, 64,254, 7, 0,224,255,255,
- 255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247,
- 0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 7,
- 255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
- 255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,255,
- 0, 0,224,255,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0,
- 0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192,255,255,
- 0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 3, 4, 0, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11, 12,
+ 0, 0, 13, 0, 0, 0, 14, 0, 15, 0, 0, 0, 0, 16, 0, 0,
+ 17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
+ 26, 27, 28, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 29,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0,
+ 5, 6, 0, 0, 7, 8, 0, 0, 8, 0, 9, 10, 0, 0, 11, 0,
+ 0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
+ 22, 23, 0, 0, 0, 24, 0, 0, 25, 0, 26, 0, 0, 27, 0, 0,
+ 28, 0, 0, 0, 16, 16, 16, 16, 29, 9, 0, 30, 31, 32, 16, 33,
+ 34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40, 0,
+ 0, 0, 0, 41, 0, 0, 42, 16, 43, 0, 44, 0, 45, 46, 16, 16,
+ 47, 48, 49, 16, 16, 16, 16, 38, 0, 0, 0, 0, 0, 66, 0, 0,
+ 0, 0, 0, 16, 0, 2, 0, 0, 4, 0, 0, 2, 0, 0,240, 3,
+ 0, 6, 0, 0, 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0,
+ 0,254, 15, 7, 4, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0,
+ 0, 0, 0,120,191,255,247,255,255,255,255,255, 63, 0,255,255,
+ 63,255, 87, 32, 2, 1, 24, 0,144, 80,184, 0,248, 0, 0, 0,
+ 0, 0,224, 0, 2, 0, 1,128, 0, 0, 48, 0,224, 0, 0, 24,
+ 0, 0, 33, 0, 0, 0, 1, 32, 0, 0,128, 2, 0,224, 0, 0,
+ 0,240, 3,192, 0, 64,254, 7, 0,224,255,255, 63, 0, 0, 0,
+ 254,255, 0, 4, 0,128,252,247, 0,254,255,255,255,255,255, 7,
+ 255,255,255, 63,192,255,255,255,255,255, 0, 0, 0, 0,240,255,
+ 0, 0,224,255, 0,240, 0, 0, 0,255, 0,252, 0,255, 0, 0,
+ 0,192,255,255, 0,240,255,255,255,255,255,247,191,255,255,255,
};
static inline unsigned
@@ -75,7 +70,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
_hb_emoji_is_Extended_Pictographic (unsigned u)
{
- return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+ return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
}
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 83ead6398..9a6471e52 100644
--- a/src/hb-unicode.cc
+++ b/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.
@@ -281,7 +281,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
*
* Attaches a user-data key/data pair to the specified Unicode-functions structure.
*
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
*
* Since: 0.9.2
**/
@@ -308,8 +308,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
* Since: 0.9.2
**/
void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
- hb_user_data_key_t *key)
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (ufuncs, key);
}
@@ -340,7 +340,7 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
* Tests whether the specified Unicode-functions structure
* is immutable.
*
- * Return value: %true if @ufuncs is immutable, %false otherwise
+ * Return value: `true` if @ufuncs is immutable, `false` otherwise
*
* Since: 0.9.2
**/
@@ -377,20 +377,30 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \
hb_destroy_func_t destroy) \
{ \
if (hb_object_is_immutable (ufuncs)) \
- return; \
+ goto fail; \
+ \
+ if (!func) \
+ { \
+ if (destroy) \
+ destroy (user_data); \
+ destroy = nullptr; \
+ user_data = ufuncs->parent->user_data.name; \
+ } \
\
if (ufuncs->destroy.name) \
ufuncs->destroy.name (ufuncs->user_data.name); \
\
- if (func) { \
+ if (func) \
ufuncs->func.name = func; \
- ufuncs->user_data.name = user_data; \
- ufuncs->destroy.name = destroy; \
- } else { \
+ else \
ufuncs->func.name = ufuncs->parent->func.name; \
- ufuncs->user_data.name = ufuncs->parent->user_data.name; \
- ufuncs->destroy.name = nullptr; \
- } \
+ ufuncs->user_data.name = user_data; \
+ ufuncs->destroy.name = destroy; \
+ return; \
+ \
+fail: \
+ if (destroy) \
+ destroy (user_data); \
}
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
@@ -421,7 +431,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
* Calls the composition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @a and @b composed, %false otherwise
+ * Return value: `true` if @a and @b composed, `false` otherwise
*
* Since: 0.9.2
**/
@@ -446,7 +456,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
* Calls the decomposition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @ab was decomposed, %false otherwise
+ * Return value: `true` if @ab was decomposed, `false` otherwise
*
* Since: 0.9.2
**/
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index c04ee15a0..faa8d6792 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -317,8 +317,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
HB_EXTERN void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
- hb_user_data_key_t *key);
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key);
HB_EXTERN void
@@ -429,7 +429,7 @@ typedef hb_script_t (*hb_unicode_script_func_t) (hb_unicode_funcs_t *ufuncs,
* The method must return an #hb_bool_t indicating the success
* of the composition.
*
- * Return value: %true is @a,@b composed, %false otherwise
+ * Return value: `true` is @a,@b composed, `false` otherwise
*
**/
typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -453,7 +453,7 @@ typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
* output parameters (if successful). The method must return an
* #hb_bool_t indicating the success of the composition.
*
- * Return value: %true if @ab decomposed, %false otherwise
+ * Return value: `true` if @ab decomposed, `false` otherwise
*
**/
typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh
index 4c28bb0cd..39aaee5ba 100644
--- a/src/hb-unicode.hh
+++ b/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/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 3dc4c0937..9648e0266 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -355,7 +355,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
return nullptr;
}
- memcpy(new_sfnt_data, orig_sfnt_data, length);
+ hb_memcpy(new_sfnt_data, orig_sfnt_data, length);
OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
name.format = 0;
@@ -478,11 +478,11 @@ populate_log_font (LOGFONTW *lf,
hb_font_t *font,
unsigned int font_size)
{
- memset (lf, 0, sizeof (*lf));
+ hb_memset (lf, 0, sizeof (*lf));
lf->lfHeight = - (int) font_size;
lf->lfCharSet = DEFAULT_CHARSET;
- memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
+ hb_memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
return true;
}
@@ -878,7 +878,8 @@ retry:
if (backward)
hb_buffer_reverse (buffer);
- buffer->unsafe_to_break_all ();
+ buffer->clear_glyph_flags ();
+ buffer->unsafe_to_break ();
/* Wow, done! */
return true;
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index b0a1e5e96..9b52f5ca9 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -29,14 +29,18 @@
#include "hb.hh"
#include "hb-array.hh"
+#include "hb-meta.hh"
#include "hb-null.hh"
-template <typename Type>
+template <typename Type,
+ bool sorted=false>
struct hb_vector_t
{
typedef Type item_t;
static constexpr unsigned item_size = hb_static_size (Type);
+ using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type;
+ using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type;
hb_vector_t () = default;
hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t ()
@@ -49,14 +53,16 @@ struct hb_vector_t
hb_requires (hb_is_iterable (Iterable))>
hb_vector_t (const Iterable &o) : hb_vector_t ()
{
- if (hb_iter (o).is_random_access_iterator)
- alloc (hb_len (hb_iter (o)));
- hb_copy (o, *this);
+ auto iter = hb_iter (o);
+ if (iter.is_random_access_iterator)
+ alloc (hb_len (iter));
+ hb_copy (iter, *this);
}
hb_vector_t (const hb_vector_t &o) : hb_vector_t ()
{
alloc (o.length);
- hb_copy (o, *this);
+ if (unlikely (in_error ())) return;
+ copy_vector (o);
}
hb_vector_t (hb_vector_t &&o)
{
@@ -67,9 +73,8 @@ struct hb_vector_t
}
~hb_vector_t () { fini (); }
- private:
- int allocated = 0; /* == -1 means allocation failed. */
public:
+ int allocated = 0; /* == -1 means allocation failed. */
unsigned int length = 0;
public:
Type *arrayZ = nullptr;
@@ -79,24 +84,25 @@ struct hb_vector_t
allocated = length = 0;
arrayZ = nullptr;
}
+ void init0 ()
+ {
+ }
void fini ()
{
+ shrink_vector (0);
hb_free (arrayZ);
init ();
}
- void fini_deep ()
- {
- unsigned int count = length;
- for (unsigned int i = 0; i < count; i++)
- arrayZ[i].fini ();
- fini ();
- }
void reset ()
{
if (unlikely (in_error ()))
- allocated = length; // Big hack!
+ /* Big Hack! We don't know the true allocated size before
+ * an allocation failure happened. But we know it was at
+ * least as big as length. Restore it to that and continue
+ * as if error did not happen. */
+ allocated = length;
resize (0);
}
@@ -111,7 +117,10 @@ struct hb_vector_t
{
reset ();
alloc (o.length);
- hb_copy (o, *this);
+ if (unlikely (in_error ())) return *this;
+
+ copy_vector (o);
+
return *this;
}
hb_vector_t& operator = (hb_vector_t &&o)
@@ -121,7 +130,7 @@ struct hb_vector_t
}
hb_bytes_t as_bytes () const
- { return hb_bytes_t ((const char *) arrayZ, length * item_size); }
+ { return hb_bytes_t ((const char *) arrayZ, get_size ()); }
bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
bool operator != (const hb_vector_t &o) const { return !(*this == o); }
@@ -152,25 +161,21 @@ struct hb_vector_t
template <typename T>
hb_vector_t& operator << (T&& v) { push (std::forward<T> (v)); return *this; }
- hb_array_t< Type> as_array () { return hb_array (arrayZ, length); }
- hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); }
+ array_t as_array () { return hb_array (arrayZ, length); }
+ c_array_t as_array () const { return hb_array (arrayZ, length); }
/* Iterator. */
- typedef hb_array_t<const Type> iter_t;
- typedef hb_array_t< Type> writer_t;
+ typedef c_array_t iter_t;
+ typedef array_t writer_t;
iter_t iter () const { return as_array (); }
writer_t writer () { return as_array (); }
operator iter_t () const { return iter (); }
operator writer_t () { return writer (); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
- { return as_array ().sub_array (start_offset, count); }
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_array ().sub_array (start_offset, count); }
+ /* Faster range-based for loop. */
+ Type *begin () const { return arrayZ; }
+ Type *end () const { return arrayZ + length; }
+
hb_sorted_array_t<Type> as_sorted_array ()
{ return hb_sorted_array (arrayZ, length); }
@@ -187,9 +192,12 @@ struct hb_vector_t
{
if (unlikely (!resize (length + 1)))
return &Crap (Type);
- return &arrayZ[length - 1];
+ return std::addressof (arrayZ[length - 1]);
}
- template <typename T>
+ template <typename T,
+ typename T2 = Type,
+ hb_enable_if (!std::is_copy_constructible<T2>::value &&
+ std::is_copy_assignable<T>::value)>
Type *push (T&& v)
{
Type *p = push ();
@@ -201,9 +209,133 @@ struct hb_vector_t
*p = std::forward<T> (v);
return p;
}
+ template <typename T,
+ typename T2 = Type,
+ hb_enable_if (std::is_copy_constructible<T2>::value)>
+ Type *push (T&& v)
+ {
+ if (unlikely (!alloc (length + 1)))
+ // If push failed to allocate then don't copy v, since this may cause
+ // the created copy to leak memory since we won't have stored a
+ // reference to it.
+ return &Crap (Type);
+
+ /* Emplace. */
+ length++;
+ Type *p = std::addressof (arrayZ[length - 1]);
+ return new (p) Type (std::forward<T> (v));
+ }
bool in_error () const { return allocated < 0; }
+ template <typename T = Type,
+ hb_enable_if (hb_is_trivially_copy_assignable(T))>
+ Type *
+ realloc_vector (unsigned new_allocated)
+ {
+ return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+ }
+ template <typename T = Type,
+ hb_enable_if (!hb_is_trivially_copy_assignable(T))>
+ Type *
+ realloc_vector (unsigned new_allocated)
+ {
+ Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type));
+ if (likely (new_array))
+ {
+ for (unsigned i = 0; i < length; i++)
+ {
+ new (std::addressof (new_array[i])) Type ();
+ new_array[i] = std::move (arrayZ[i]);
+ arrayZ[i].~Type ();
+ }
+ hb_free (arrayZ);
+ }
+ return new_array;
+ }
+
+ template <typename T = Type,
+ hb_enable_if (hb_is_trivially_constructible(T))>
+ void
+ grow_vector (unsigned size)
+ {
+ memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ length = size;
+ }
+ template <typename T = Type,
+ hb_enable_if (!hb_is_trivially_constructible(T))>
+ void
+ grow_vector (unsigned size)
+ {
+ while (length < size)
+ {
+ length++;
+ new (std::addressof (arrayZ[length - 1])) Type ();
+ }
+ }
+
+ template <typename T = Type,
+ hb_enable_if (hb_is_trivially_copyable (T))>
+ void
+ copy_vector (const hb_vector_t &other)
+ {
+ length = other.length;
+#ifndef HB_OPTIMIZE_SIZE
+ if (sizeof (T) >= sizeof (long long))
+ /* This runs faster because of alignment. */
+ for (unsigned i = 0; i < length; i++)
+ arrayZ[i] = other.arrayZ[i];
+ else
+#endif
+ 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];
+ }
+ }
+
+ void
+ shrink_vector (unsigned size)
+ {
+ while ((unsigned) length > size)
+ {
+ arrayZ[(unsigned) length - 1].~Type ();
+ length--;
+ }
+ }
+
+ void
+ shift_down_vector (unsigned i)
+ {
+ for (; i < length; i++)
+ arrayZ[i - 1] = std::move (arrayZ[i]);
+ }
+
/* Allocate for size but don't adjust length. */
bool alloc (unsigned int size)
{
@@ -225,7 +357,7 @@ struct hb_vector_t
(new_allocated < (unsigned) allocated) ||
hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
- new_array = (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+ new_array = realloc_vector (new_allocated);
if (unlikely (!new_array))
{
@@ -239,14 +371,22 @@ struct hb_vector_t
return true;
}
- bool resize (int size_)
+ bool resize (int size_, bool initialize = true)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (!alloc (size))
return false;
if (size > length)
- memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ {
+ if (initialize)
+ grow_vector (size);
+ }
+ else if (size < length)
+ {
+ if (initialize)
+ shrink_vector (size);
+ }
length = size;
return true;
@@ -255,48 +395,48 @@ struct hb_vector_t
Type pop ()
{
if (!length) return Null (Type);
- return std::move (arrayZ[--length]); /* Does this move actually work? */
+ Type v {std::move (arrayZ[length - 1])};
+ arrayZ[length - 1].~Type ();
+ length--;
+ return v;
}
- void remove (unsigned int i)
+ void remove_ordered (unsigned int i)
{
if (unlikely (i >= length))
return;
- memmove (static_cast<void *> (&arrayZ[i]),
- static_cast<void *> (&arrayZ[i + 1]),
- (length - i - 1) * sizeof (Type));
+ shift_down_vector (i + 1);
+ arrayZ[length - 1].~Type ();
length--;
}
- void shrink (int size_)
+ template <bool Sorted = sorted,
+ hb_enable_if (!Sorted)>
+ void remove_unordered (unsigned int i)
{
- unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
- if (size < length)
- length = size;
+ if (unlikely (i >= length))
+ return;
+ if (i != length - 1)
+ arrayZ[i] = std::move (arrayZ[length - 1]);
+ arrayZ[length - 1].~Type ();
+ length--;
}
- template <typename T>
- Type *find (T v)
- {
- for (unsigned int i = 0; i < length; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
- return nullptr;
- }
- template <typename T>
- const Type *find (T v) const
+ void shrink (int size_)
{
- for (unsigned int i = 0; i < length; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
- return nullptr;
+ unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
+ if (size >= length)
+ return;
+
+ shrink_vector (size);
}
- void qsort (int (*cmp)(const void*, const void*))
+
+ /* Sorting API. */
+ void qsort (int (*cmp)(const void*, const void*) = Type::cmp)
{ as_array ().qsort (cmp); }
- void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
- { as_array ().qsort (start, end); }
+ /* Unsorted search API. */
template <typename T>
Type *lsearch (const T &x, Type *not_found = nullptr)
{ return as_array ().lsearch (x, not_found); }
@@ -306,47 +446,25 @@ struct hb_vector_t
template <typename T>
bool lfind (const T &x, unsigned *pos = nullptr) const
{ return as_array ().lfind (x, pos); }
-};
-template <typename Type>
-struct hb_sorted_vector_t : hb_vector_t<Type>
-{
- hb_sorted_vector_t () = default;
- ~hb_sorted_vector_t () = default;
- hb_sorted_vector_t (hb_sorted_vector_t& o) = default;
- hb_sorted_vector_t (hb_sorted_vector_t &&o) = default;
- hb_sorted_vector_t (std::initializer_list<Type> lst) : hb_vector_t<Type> (lst) {}
- template <typename Iterable,
- hb_requires (hb_is_iterable (Iterable))>
- hb_sorted_vector_t (const Iterable &o) : hb_vector_t<Type> (o) {}
- hb_sorted_vector_t& operator = (const hb_sorted_vector_t &o) = default;
- hb_sorted_vector_t& operator = (hb_sorted_vector_t &&o) = default;
- friend void swap (hb_sorted_vector_t& a, hb_sorted_vector_t& b)
- { hb_swap ((hb_vector_t<Type>&) (a), (hb_vector_t<Type>&) (b)); }
-
- hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->length); }
- hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); }
-
- /* Iterator. */
- typedef hb_sorted_array_t<const Type> const_iter_t;
- typedef hb_sorted_array_t< Type> iter_t;
- const_iter_t iter () const { return as_array (); }
- const_iter_t citer () const { return as_array (); }
- iter_t iter () { return as_array (); }
- operator iter_t () { return iter (); }
- operator const_iter_t () const { return iter (); }
-
- template <typename T>
+ /* Sorted search API. */
+ template <typename T,
+ bool Sorted=sorted, hb_enable_if (Sorted)>
Type *bsearch (const T &x, Type *not_found = nullptr)
{ return as_array ().bsearch (x, not_found); }
- template <typename T>
+ template <typename T,
+ bool Sorted=sorted, hb_enable_if (Sorted)>
const Type *bsearch (const T &x, const Type *not_found = nullptr) const
{ return as_array ().bsearch (x, not_found); }
- template <typename T>
+ template <typename T,
+ bool Sorted=sorted, hb_enable_if (Sorted)>
bool bfind (const T &x, unsigned int *i = nullptr,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{ return as_array ().bfind (x, i, not_found, to_store); }
};
+template <typename Type>
+using hb_sorted_vector_t = hb_vector_t<Type, true>;
+
#endif /* HB_VECTOR_HH */
diff --git a/src/hb-version.h b/src/hb-version.h
index 1a4f0bf62..1070262a3 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
-#define HB_VERSION_MAJOR 3
+#define HB_VERSION_MAJOR 6
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 1
+#define HB_VERSION_MINOR 0
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "3.1.1"
+#define HB_VERSION_STRING "6.0.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/src/hb.hh b/src/hb.hh
index 1f1426752..410d090d3 100644
--- a/src/hb.hh
+++ b/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"
@@ -126,6 +126,7 @@
/* Ignored intentionally. */
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic ignored "-Wformat-zero-length"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
@@ -183,7 +184,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>
@@ -447,6 +448,7 @@ static int HB_UNUSED _hb_errno = 0;
#ifndef HB_USE_ATEXIT
# define HB_USE_ATEXIT 0
#endif
+#ifndef hb_atexit
#if !HB_USE_ATEXIT
# define hb_atexit(_) HB_STMT_START { if (0) (_) (); } HB_STMT_END
#else /* HB_USE_ATEXIT */
@@ -457,6 +459,7 @@ static int HB_UNUSED _hb_errno = 0;
# define hb_atexit(f) static hb_atexit_t<f> _hb_atexit_##__LINE__;
# endif
#endif
+#endif
/* Lets assert int types. Saves trouble down the road. */
static_assert ((sizeof (hb_codepoint_t) == 4), "");
@@ -468,6 +471,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"
diff --git a/src/main.cc b/src/main.cc
index 1ab013cd3..bb18ebe38 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -42,7 +42,7 @@
#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
static void
svg_dump (hb_face_t *face, unsigned face_index)
{
@@ -58,7 +58,8 @@ svg_dump (hb_face_t *face, unsigned face_index)
const char *data = hb_blob_get_data (blob, &length);
char output_path[255];
- sprintf (output_path, "out/svg-%u-%u.svg%s",
+ snprintf (output_path, sizeof output_path,
+ "out/svg-%u-%u.svg%s",
glyph_id,
face_index,
// append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
@@ -112,7 +113,7 @@ png_dump (hb_face_t *face, unsigned face_index)
const char *data = hb_blob_get_data (blob, &length);
char output_path[255];
- sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
+ snprintf (output_path, sizeof output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
FILE *f = fopen (output_path, "wb");
fwrite (data, 1, length, f);
@@ -129,48 +130,60 @@ png_dump (hb_face_t *face, unsigned face_index)
hb_font_destroy (font);
}
-struct user_data_t
+struct draw_data_t
{
FILE *f;
hb_position_t ascender;
};
static void
-move_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
+move_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+ hb_draw_state_t *,
+ float to_x, float to_y,
+ void *)
{
- fprintf (user_data.f, "M%d,%d", to_x, user_data.ascender - to_y);
+ fprintf (draw_data->f, "M%g,%g", to_x, draw_data->ascender - to_y);
}
static void
-line_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
+line_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+ hb_draw_state_t *,
+ float to_x, float to_y,
+ void *)
{
- fprintf (user_data.f, "L%d,%d", to_x, user_data.ascender - to_y);
+ fprintf (draw_data->f, "L%g,%g", to_x, draw_data->ascender - to_y);
}
static void
-quadratic_to (hb_position_t control_x, hb_position_t control_y,
- hb_position_t to_x, hb_position_t to_y,
- user_data_t &user_data)
+quadratic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+ hb_draw_state_t *,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *)
{
- fprintf (user_data.f, "Q%d,%d %d,%d", control_x, user_data.ascender - control_y,
- to_x, user_data.ascender - to_y);
+ fprintf (draw_data->f, "Q%g,%g %g,%g", control_x, draw_data->ascender - control_y,
+ to_x, draw_data->ascender - to_y);
}
static void
-cubic_to (hb_position_t control1_x, hb_position_t control1_y,
- hb_position_t control2_x, hb_position_t control2_y,
- hb_position_t to_x, hb_position_t to_y,
- user_data_t &user_data)
+cubic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+ hb_draw_state_t *,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *)
{
- fprintf (user_data.f, "C%d,%d %d,%d %d,%d", control1_x, user_data.ascender - control1_y,
- control2_x, user_data.ascender - control2_y,
- to_x, user_data.ascender - to_y);
+ fprintf (draw_data->f, "C%g,%g %g,%g %g,%g", control1_x, draw_data->ascender - control1_y,
+ control2_x, draw_data->ascender - control2_y,
+ to_x, draw_data->ascender - to_y);
}
static void
-close_path (user_data_t &user_data)
+close_path (hb_draw_funcs_t *, draw_data_t *draw_data,
+ hb_draw_state_t *,
+ void *)
{
- fprintf (user_data.f, "Z");
+ fprintf (draw_data->f, "Z");
}
static void
@@ -212,15 +225,15 @@ layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index
}
char output_path[255];
- sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
+ snprintf (output_path, sizeof output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
FILE *f = fopen (output_path, "wb");
fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
" viewBox=\"%d %d %d %d\">\n",
extents.x_bearing, 0,
extents.x_bearing + extents.width, -extents.height);
- user_data_t user_data;
- user_data.ascender = extents.y_bearing;
- user_data.f = f;
+ draw_data_t draw_data;
+ draw_data.ascender = extents.y_bearing;
+ draw_data.f = f;
for (unsigned layer = 0; layer < num_layers; ++layer)
{
@@ -232,8 +245,7 @@ layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index
if (hb_color_get_alpha (color) != 255)
fprintf (f, "fill-opacity=\"%.3f\"", (double) hb_color_get_alpha (color) / 255.);
fprintf (f, "d=\"");
- if (!hb_font_draw_glyph (font, layers[layer].glyph, funcs, &user_data))
- printf ("Failed to decompose layer %d while %d\n", layers[layer].glyph, gid);
+ hb_font_get_glyph_shape (font, layers[layer].glyph, funcs, &draw_data);
fprintf (f, "\"/>\n");
}
@@ -263,17 +275,16 @@ dump_glyphs (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
}
char output_path[255];
- sprintf (output_path, "out/%u-%u.svg", face_index, gid);
+ snprintf (output_path, sizeof output_path, "out/%u-%u.svg", face_index, gid);
FILE *f = fopen (output_path, "wb");
fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
" viewBox=\"%d %d %d %d\"><path d=\"",
extents.x_bearing, 0,
extents.x_bearing + extents.width, font_extents.ascender - font_extents.descender);
- user_data_t user_data;
- user_data.ascender = font_extents.ascender;
- user_data.f = f;
- if (!hb_font_draw_glyph (font, gid, funcs, &user_data))
- printf ("Failed to decompose gid: %d\n", gid);
+ draw_data_t draw_data;
+ draw_data.ascender = font_extents.ascender;
+ draw_data.f = f;
+ hb_font_get_glyph_shape (font, gid, funcs, &draw_data);
fprintf (f, "\"/></svg>");
fclose (f);
}
@@ -300,11 +311,11 @@ dump_glyphs (hb_blob_t *blob, const char *font_name)
fclose (font_name_file);
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to);
- hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to);
- hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to);
- hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to);
- hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path);
+ hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
+ hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
+ hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, nullptr, nullptr);
+ hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
+ hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
unsigned num_faces = hb_face_count (blob);
for (unsigned face_index = 0; face_index < num_faces; ++face_index)
@@ -482,12 +493,12 @@ print_layout_info_using_private_api (hb_blob_t *blob)
gdef.has_glyph_classes () ? "" : "no ");
printf (" Has %smark attachment types\n",
gdef.has_mark_attachment_types () ? "" : "no ");
- printf (" Has %sattach points\n",
- gdef.has_attach_points () ? "" : "no ");
+ printf (" Has %sattach list\n",
+ gdef.has_attach_list () ? "" : "no ");
printf (" Has %slig carets\n",
gdef.has_lig_carets () ? "" : "no ");
- printf (" Has %smark sets\n",
- gdef.has_mark_sets () ? "" : "no ");
+ printf (" Has %smark glyph sets\n",
+ gdef.has_mark_glyph_sets () ? "" : "no ");
break;
}
}
@@ -512,7 +523,7 @@ main (int argc, char **argv)
#ifndef MAIN_CC_NO_PRIVATE_API
print_layout_info_using_private_api (blob);
#endif
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
dump_glyphs (blob, argv[1]);
#endif
hb_blob_destroy (blob);
diff --git a/src/meson.build b/src/meson.build
index bda44c683..5d01d9862 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -3,7 +3,7 @@ hb_version_h = configure_file(
input: 'hb-version.h.in',
output: 'hb-version.h',
install: true,
- install_dir: join_paths(get_option('includedir'), meson.project_name()))
+ install_dir: get_option('includedir') / meson.project_name())
# Base and default-included sources and headers
hb_base_sources = files(
@@ -29,6 +29,7 @@ hb_base_sources = files(
'hb-blob.cc',
'hb-blob.hh',
'hb-buffer-serialize.cc',
+ 'hb-buffer-verify.cc',
'hb-buffer.cc',
'hb-buffer.hh',
'hb-cache.hh',
@@ -54,8 +55,8 @@ hb_base_sources = files(
'hb-map.cc',
'hb-map.hh',
'hb-meta.hh',
- 'hb-ms-feature-ranges.cc',
'hb-ms-feature-ranges.hh',
+ 'hb-multimap.hh',
'hb-mutex.hh',
'hb-null.hh',
'hb-number.cc',
@@ -92,6 +93,74 @@ hb_base_sources = files(
'hb-ot-layout-gdef-table.hh',
'hb-ot-layout-gpos-table.hh',
'hb-ot-layout-gsub-table.hh',
+ 'OT/glyf/glyf.hh',
+ 'OT/glyf/glyf-helpers.hh',
+ 'OT/glyf/loca.hh',
+ 'OT/glyf/path-builder.hh',
+ 'OT/glyf/Glyph.hh',
+ 'OT/glyf/GlyphHeader.hh',
+ 'OT/glyf/SimpleGlyph.hh',
+ 'OT/glyf/CompositeGlyph.hh',
+ 'OT/glyf/SubsetGlyph.hh',
+ 'OT/Layout/types.hh',
+ 'OT/Layout/Common/Coverage.hh',
+ 'OT/Layout/Common/CoverageFormat1.hh',
+ 'OT/Layout/Common/CoverageFormat2.hh',
+ 'OT/Layout/Common/RangeRecord.hh',
+ 'OT/Layout/GPOS/AnchorFormat1.hh',
+ 'OT/Layout/GPOS/AnchorFormat2.hh',
+ 'OT/Layout/GPOS/AnchorFormat3.hh',
+ 'OT/Layout/GPOS/Anchor.hh',
+ 'OT/Layout/GPOS/AnchorMatrix.hh',
+ 'OT/Layout/GPOS/ChainContextPos.hh',
+ 'OT/Layout/GPOS/Common.hh',
+ 'OT/Layout/GPOS/ContextPos.hh',
+ 'OT/Layout/GPOS/CursivePosFormat1.hh',
+ 'OT/Layout/GPOS/CursivePos.hh',
+ 'OT/Layout/GPOS/ExtensionPos.hh',
+ 'OT/Layout/GPOS/GPOS.hh',
+ 'OT/Layout/GPOS/LigatureArray.hh',
+ 'OT/Layout/GPOS/MarkArray.hh',
+ 'OT/Layout/GPOS/MarkBasePosFormat1.hh',
+ 'OT/Layout/GPOS/MarkBasePos.hh',
+ 'OT/Layout/GPOS/MarkLigPosFormat1.hh',
+ 'OT/Layout/GPOS/MarkLigPos.hh',
+ 'OT/Layout/GPOS/MarkMarkPosFormat1.hh',
+ 'OT/Layout/GPOS/MarkMarkPos.hh',
+ 'OT/Layout/GPOS/MarkRecord.hh',
+ 'OT/Layout/GPOS/PairPosFormat1.hh',
+ 'OT/Layout/GPOS/PairPosFormat2.hh',
+ 'OT/Layout/GPOS/PairPos.hh',
+ 'OT/Layout/GPOS/PairSet.hh',
+ 'OT/Layout/GPOS/PairValueRecord.hh',
+ 'OT/Layout/GPOS/PosLookup.hh',
+ 'OT/Layout/GPOS/PosLookupSubTable.hh',
+ 'OT/Layout/GPOS/SinglePosFormat1.hh',
+ 'OT/Layout/GPOS/SinglePosFormat2.hh',
+ 'OT/Layout/GPOS/SinglePos.hh',
+ 'OT/Layout/GPOS/ValueFormat.hh',
+ 'OT/Layout/GSUB/AlternateSet.hh',
+ 'OT/Layout/GSUB/AlternateSubstFormat1.hh',
+ 'OT/Layout/GSUB/AlternateSubst.hh',
+ 'OT/Layout/GSUB/ChainContextSubst.hh',
+ 'OT/Layout/GSUB/Common.hh',
+ 'OT/Layout/GSUB/ContextSubst.hh',
+ 'OT/Layout/GSUB/ExtensionSubst.hh',
+ 'OT/Layout/GSUB/GSUB.hh',
+ 'OT/Layout/GSUB/Ligature.hh',
+ 'OT/Layout/GSUB/LigatureSet.hh',
+ 'OT/Layout/GSUB/LigatureSubstFormat1.hh',
+ 'OT/Layout/GSUB/LigatureSubst.hh',
+ 'OT/Layout/GSUB/MultipleSubstFormat1.hh',
+ 'OT/Layout/GSUB/MultipleSubst.hh',
+ 'OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh',
+ 'OT/Layout/GSUB/ReverseChainSingleSubst.hh',
+ 'OT/Layout/GSUB/Sequence.hh',
+ 'OT/Layout/GSUB/SingleSubstFormat1.hh',
+ 'OT/Layout/GSUB/SingleSubstFormat2.hh',
+ 'OT/Layout/GSUB/SingleSubst.hh',
+ 'OT/Layout/GSUB/SubstLookup.hh',
+ 'OT/Layout/GSUB/SubstLookupSubTable.hh',
'hb-ot-layout-gsubgpos.hh',
'hb-ot-layout-jstf-table.hh',
'hb-ot-layout.cc',
@@ -113,30 +182,29 @@ hb_base_sources = files(
'hb-ot-os2-unicode-ranges.hh',
'hb-ot-post-macroman.hh',
'hb-ot-post-table.hh',
- 'hb-ot-shape-complex-arabic-fallback.hh',
- 'hb-ot-shape-complex-arabic-joining-list.hh',
- 'hb-ot-shape-complex-arabic-table.hh',
- 'hb-ot-shape-complex-arabic-win1256.hh',
- 'hb-ot-shape-complex-arabic.cc',
- 'hb-ot-shape-complex-arabic.hh',
- 'hb-ot-shape-complex-default.cc',
- 'hb-ot-shape-complex-hangul.cc',
- 'hb-ot-shape-complex-hebrew.cc',
- 'hb-ot-shape-complex-indic-table.cc',
- 'hb-ot-shape-complex-indic.cc',
- 'hb-ot-shape-complex-indic.hh',
- 'hb-ot-shape-complex-khmer.cc',
- 'hb-ot-shape-complex-khmer.hh',
- 'hb-ot-shape-complex-myanmar.cc',
- 'hb-ot-shape-complex-myanmar.hh',
- 'hb-ot-shape-complex-syllabic.cc',
- 'hb-ot-shape-complex-syllabic.hh',
- 'hb-ot-shape-complex-thai.cc',
- 'hb-ot-shape-complex-use-table.hh',
- 'hb-ot-shape-complex-use.cc',
- 'hb-ot-shape-complex-vowel-constraints.cc',
- 'hb-ot-shape-complex-vowel-constraints.hh',
- 'hb-ot-shape-complex.hh',
+ 'hb-ot-shaper-arabic-fallback.hh',
+ 'hb-ot-shaper-arabic-joining-list.hh',
+ 'hb-ot-shaper-arabic-pua.hh',
+ 'hb-ot-shaper-arabic-table.hh',
+ 'hb-ot-shaper-arabic-win1256.hh',
+ 'hb-ot-shaper-arabic.cc',
+ 'hb-ot-shaper-arabic.hh',
+ 'hb-ot-shaper-default.cc',
+ 'hb-ot-shaper-hangul.cc',
+ 'hb-ot-shaper-hebrew.cc',
+ 'hb-ot-shaper-indic-table.cc',
+ 'hb-ot-shaper-indic.cc',
+ 'hb-ot-shaper-indic.hh',
+ 'hb-ot-shaper-khmer.cc',
+ 'hb-ot-shaper-myanmar.cc',
+ 'hb-ot-shaper-syllabic.cc',
+ 'hb-ot-shaper-syllabic.hh',
+ 'hb-ot-shaper-thai.cc',
+ 'hb-ot-shaper-use-table.hh',
+ 'hb-ot-shaper-use.cc',
+ 'hb-ot-shaper-vowel-constraints.cc',
+ 'hb-ot-shaper-vowel-constraints.hh',
+ 'hb-ot-shaper.hh',
'hb-ot-shape-fallback.cc',
'hb-ot-shape-fallback.hh',
'hb-ot-shape-normalize.cc',
@@ -184,19 +252,19 @@ hb_base_ragel_generated_sources = files(
'hb-buffer-deserialize-json.hh',
'hb-buffer-deserialize-text.hh',
'hb-number-parser.hh',
- 'hb-ot-shape-complex-indic-machine.hh',
- 'hb-ot-shape-complex-khmer-machine.hh',
- 'hb-ot-shape-complex-myanmar-machine.hh',
- 'hb-ot-shape-complex-use-machine.hh',
+ 'hb-ot-shaper-indic-machine.hh',
+ 'hb-ot-shaper-khmer-machine.hh',
+ 'hb-ot-shaper-myanmar-machine.hh',
+ 'hb-ot-shaper-use-machine.hh',
)
hb_base_ragel_sources = [
'hb-buffer-deserialize-json.rl',
'hb-buffer-deserialize-text.rl',
'hb-number-parser.rl',
- 'hb-ot-shape-complex-indic-machine.rl',
- 'hb-ot-shape-complex-khmer-machine.rl',
- 'hb-ot-shape-complex-myanmar-machine.rl',
- 'hb-ot-shape-complex-use-machine.rl',
+ 'hb-ot-shaper-indic-machine.rl',
+ 'hb-ot-shaper-khmer-machine.rl',
+ 'hb-ot-shaper-myanmar-machine.rl',
+ 'hb-ot-shaper-use-machine.rl',
]
hb_base_headers = files(
@@ -205,6 +273,7 @@ hb_base_headers = files(
'hb-blob.h',
'hb-buffer.h',
'hb-common.h',
+ 'hb-cplusplus.hh',
'hb-deprecated.h',
'hb-draw.h',
'hb-face.h',
@@ -266,6 +335,7 @@ hb_subset_sources = files(
'hb-ot-cff1-table.cc',
'hb-ot-cff2-table.cc',
'hb-static.cc',
+ 'hb-subset-accelerator.hh',
'hb-subset-cff-common.cc',
'hb-subset-cff-common.hh',
'hb-subset-cff1.cc',
@@ -276,11 +346,23 @@ hb_subset_sources = files(
'hb-subset-input.hh',
'hb-subset-plan.cc',
'hb-subset-plan.hh',
+ 'hb-subset-repacker.cc',
+ 'graph/gsubgpos-context.cc',
+ 'graph/gsubgpos-context.hh',
+ 'graph/gsubgpos-graph.hh',
+ 'graph/pairpos-graph.hh',
+ 'graph/markbasepos-graph.hh',
+ 'graph/coverage-graph.hh',
+ 'graph/classdef-graph.hh',
+ 'graph/split-helpers.hh',
'hb-subset.cc',
'hb-subset.hh',
)
-hb_subset_headers = files('hb-subset.h')
+hb_subset_headers = files(
+ 'hb-subset.h',
+ 'hb-subset-repacker.h'
+)
hb_gobject_sources = files(
'hb-gobject-structs.cc'
@@ -298,7 +380,9 @@ if not has_ragel and get_option('ragel_subproject')
has_ragel = true
endif
if not has_ragel
- warning('You have to install ragel if you are going to develop HarfBuzz itself')
+ if not meson.is_subproject()
+ warning('You have to install ragel if you are going to develop HarfBuzz itself')
+ endif
else
ragel_helper = find_program('gen-ragel-artifacts.py')
foreach rl : hb_base_ragel_sources
@@ -331,33 +415,40 @@ harfbuzz_deps = [thread_dep, m_dep] + harfbuzz_extra_deps
libharfbuzz_link_language = 'c'
+hb_features = configuration_data()
+
if conf.get('HAVE_FREETYPE', 0) == 1
hb_sources += hb_ft_sources
hb_headers += hb_ft_headers
harfbuzz_deps += [freetype_dep]
+ hb_features.set('HB_HAS_FREETYPE', 1)
endif
if conf.get('HAVE_GDI', 0) == 1
hb_sources += hb_gdi_sources
hb_headers += hb_gdi_headers
harfbuzz_deps += gdi_uniscribe_deps
+ hb_features.set('HB_HAS_GDI', 1)
endif
if conf.get('HAVE_GRAPHITE2', 0) == 1
hb_sources += hb_graphite2_sources
hb_headers += hb_graphite2_headers
harfbuzz_deps += [graphite2_dep, graphite_dep]
+ hb_features.set('HB_HAS_GRAPHITE', 1)
endif
if conf.get('HAVE_GLIB', 0) == 1
hb_sources += hb_glib_sources
hb_headers += hb_glib_headers
harfbuzz_deps += [glib_dep]
+ hb_features.set('HB_HAS_GLIB', 1)
endif
if conf.get('HAVE_UNISCRIBE', 0) == 1
hb_sources += hb_uniscribe_sources
hb_headers += hb_uniscribe_headers
+ hb_features.set('HB_HAS_UNISCRIBE', 1)
endif
if conf.get('HAVE_DIRECTWRITE', 0) == 1
@@ -365,12 +456,14 @@ if conf.get('HAVE_DIRECTWRITE', 0) == 1
hb_headers += hb_directwrite_headers
# hb-directwrite needs a C++ linker
libharfbuzz_link_language = 'cpp'
+ hb_features.set('HB_HAS_DIRECTWRITE', 1)
endif
if conf.get('HAVE_CORETEXT', 0) == 1
hb_sources += hb_coretext_sources
hb_headers += hb_coretext_headers
harfbuzz_deps += coretext_deps
+ hb_features.set('HB_HAS_CORETEXT', 1)
endif
have_icu = conf.get('HAVE_ICU', 0) == 1
@@ -380,8 +473,17 @@ if have_icu and have_icu_builtin
hb_sources += hb_icu_sources
hb_headers += hb_icu_headers
harfbuzz_deps += [icu_dep]
+ hb_features.set('HB_HAS_ICU', 1)
endif
+hb_features_h = configure_file(input: 'hb-features.h.in',
+ output: 'hb-features.h',
+ configuration: hb_features,
+ install: true,
+ install_dir: get_option('includedir') / meson.project_name())
+
+# Base and default-included sources and headers
+
# harfbuzz
gen_def = find_program('gen-def.py')
@@ -399,7 +501,7 @@ defs_list = [harfbuzz_def]
version = '0.@0@.0'.format(hb_version_int)
extra_hb_cpp_args = []
-if cpp.get_id() == 'msvc'
+if cpp.get_argument_syntax() == 'msvc'
if get_option('default_library') != 'static'
extra_hb_cpp_args += '-DHB_DLL_EXPORT'
endif
@@ -453,6 +555,14 @@ libharfbuzz_subset = library('harfbuzz-subset', hb_subset_sources,
link_language: 'c',
)
+custom_target('harfbuzz-subset.cc',
+ build_by_default: true,
+ output: 'harfbuzz-subset.cc',
+ input: hb_base_sources + hb_subset_sources,
+ command: [find_program('gen-harfbuzzcc.py'),
+ '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
+)
+
libharfbuzz_subset_dep = declare_dependency(
link_with: libharfbuzz_subset,
include_directories: incsrc,
@@ -461,7 +571,7 @@ libharfbuzz_subset_dep = declare_dependency(
if get_option('tests').enabled()
# TODO: MSVC gives the following,
# error LNK2019: unresolved external symbol "unsigned __int64 const * const _hb_NullPool"
- if cpp.get_id() != 'msvc'
+ if cpp.get_argument_syntax() != 'msvc'
noinst_programs = {
'main': 'main.cc',
'test-basics': 'test.cc',
@@ -471,6 +581,7 @@ if get_option('tests').enabled()
'test-ot-glyphname': 'test-ot-glyphname.cc',
'test-ot-gpos-size-params': 'test-gpos-size-params.cc',
'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc',
+ 'test-use-table': 'test-use-table.cc',
}
foreach name, source : noinst_programs
executable(name, source,
@@ -485,19 +596,23 @@ if get_option('tests').enabled()
compiled_tests = {
'test-algs': ['test-algs.cc', 'hb-static.cc'],
'test-array': ['test-array.cc'],
- 'test-repacker': ['test-repacker.cc', 'hb-static.cc'],
- 'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
'test-iter': ['test-iter.cc', 'hb-static.cc'],
+ 'test-machinery': ['test-machinery.cc', 'hb-static.cc'],
'test-map': ['test-map.cc', 'hb-static.cc'],
+ 'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
'test-number': ['test-number.cc', 'hb-number.cc'],
'test-ot-tag': ['hb-ot-tag.cc'],
+ 'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
+ 'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
+ 'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
'test-set': ['test-set.cc', 'hb-static.cc'],
+ 'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
'test-unicode-ranges': ['test-unicode-ranges.cc'],
'test-vector': ['test-vector.cc', 'hb-static.cc'],
'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
}
foreach name, source : compiled_tests
- if cpp.get_id() == 'msvc' and source.contains('hb-static.cc')
+ if cpp.get_argument_syntax() == 'msvc' and source.contains('hb-static.cc')
# TODO: MSVC doesn't like tests having hb-static.cc, fix them
continue
endif
@@ -562,14 +677,14 @@ endif
have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
cmake_config = configuration_data()
-cmake_config.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
-cmake_config.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
+cmake_config.set('libdir', get_option('prefix') / get_option('libdir'))
+cmake_config.set('includedir', get_option('prefix') / get_option('includedir'))
cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info)
cmake_config.set('have_gobject', '@0@'.format(have_gobject))
configure_file(input: 'harfbuzz-config.cmake.in',
output: 'harfbuzz-config.cmake',
configuration: cmake_config,
- install_dir: join_paths(get_option('libdir'), 'cmake', 'harfbuzz'),
+ install_dir: get_option('libdir') / 'cmake' / 'harfbuzz',
)
libharfbuzz_gobject_dep = null_dep
@@ -579,14 +694,12 @@ if have_gobject
h_templ = configure_file(
input: 'hb-gobject-enums.h.tmpl',
output: 'hb-gobject-enums-tmp.h.tmpl',
- configuration: configuration_data(),
- format: 'cmake')
+ copy: true)
cc_templ = configure_file(
input: 'hb-gobject-enums.cc.tmpl',
output: 'hb-gobject-enums-tmp.cc.tmpl',
- configuration: configuration_data(),
- format: 'cmake')
+ copy: true)
enums = gnome.mkenums('hb-gobject',
sources: hb_headers,
@@ -607,7 +720,7 @@ if have_gobject
output: 'hb-gobject-enums.h',
command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@'],
install: true,
- install_dir: join_paths(get_option('prefix'), get_option('includedir'), meson.project_name()),
+ install_dir: get_option('prefix') / get_option('includedir') / meson.project_name(),
)
hb_gobject_sources += [enum_c]
@@ -647,7 +760,7 @@ if have_gobject
nsversion: '0.0',
identifier_prefix: 'hb_',
symbol_prefix: ['hb', 'hb_gobject'],
- includes: ['GObject-2.0'],
+ includes: ['GObject-2.0', 'freetype2-2.0'],
export_packages: ['harfbuzz-gobject'],
header: 'hb-gobject.h',
install: true,
@@ -658,16 +771,10 @@ if have_gobject
'--cflags-end'])
endif
- if build_gir
- libharfbuzz_gobject_sources = hb_gen_files_gir
- else
- libharfbuzz_gobject_sources = hb_gobject_sources
- endif
-
libharfbuzz_gobject_dep = declare_dependency(
link_with: libharfbuzz_gobject,
include_directories: incsrc,
- sources: libharfbuzz_gobject_sources,
+ sources: build_gir ? hb_gen_files_gir : hb_gobject_sources,
dependencies: [glib_dep, gobject_dep])
pkgmod.generate(libharfbuzz_gobject,
@@ -694,6 +801,7 @@ if get_option('tests').enabled()
env = environment()
env.set('srcdir', meson.current_source_dir())
+ env.set('base_srcdir', meson.source_root())
env.set('builddir', meson.current_build_dir())
env.set('libs', meson.current_build_dir()) # TODO: Merge this with builddir after autotools removal
HBSOURCES = []
@@ -707,22 +815,14 @@ if get_option('tests').enabled()
endforeach
env.set('HBHEADERS', ' '.join(HBHEADERS))
- if cpp.get_id() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
- if meson.version().version_compare('>=0.55')
- dist_check_script += 'check-libstdc++'
- endif
- dist_check_script += ['check-static-inits', 'check-symbols']
+ if cpp.get_argument_syntax() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
+ dist_check_script += ['check-libstdc++', 'check-static-inits', 'check-symbols']
endif
foreach name : dist_check_script
- if name == 'check-symbols'
- test_depends = defs_list
- else
- test_depends = []
- endif
test(name, find_program(name + '.py'),
env: env,
- depends: test_depends,
+ depends: name == 'check-symbols' ? defs_list : [],
suite: ['src'],
)
endforeach
diff --git a/src/ms-use/IndicPositionalCategory-Additional.txt b/src/ms-use/IndicPositionalCategory-Additional.txt
index 83a164e49..884fee590 100644
--- a/src/ms-use/IndicPositionalCategory-Additional.txt
+++ b/src/ms-use/IndicPositionalCategory-Additional.txt
@@ -7,6 +7,7 @@
# Updated for Unicode 12.1 by Andrew Glass 2019-05-30
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
# Updated for Unicode 14.0 by Andrew Glass 2021-09-28
+# Updated for Unicode 15.0 by Andrew Glass 2022-09-16
# ================================================
# ================================================
@@ -19,9 +20,12 @@
0F7A..0F7D ; Bottom # Mn [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO # Not really below, but need to override to fit into Universal model
0F80 ; Bottom # Mn TIBETAN VOWEL SIGN REVERSED I # Not really below, but need to override to fit into Universal model
A9BF ; Bottom # Mc JAVANESE CONSONANT SIGN CAKRA
+10A38 ; Bottom # Mn KHAROSHTHI SIGN BAR ABOVE # Overriden, ccc controls order USE issue #26
11127..11129 ; Bottom # Mn [3] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN II
1112D ; Bottom # Mn CHAKMA VOWEL SIGN AI
11130 ; Bottom # Mn CHAKMA VOWEL SIGN OI
+1BF2..1BF3 ; Bottom # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN # see USE issue #20
+
# ================================================
@@ -42,12 +46,15 @@ A9BE ; Right # Mc JAVANESE CONSONANT SIGN PENGKAL # Reduced from
0F74 ; Top # Mn TIBETAN VOWEL SIGN U # Not really above, but need to override to fit into Universal model
1A18 ; Top # Mn BUGINESE VOWEL SIGN U # Workaround to allow below to occur before above by treating all below marks as above
AA35   ; Top # Mn       CHAM CONSONANT SIGN
+1112A..1112B ; Top # Mn [2] CHAKMA VOWEL SIGN U..CHAKMA VOWEL SIGN UU # see USE issue #25
+11131..11132 ; Top # Mn [2] CHAKMA O MARK..CHAKMA AU MARK # see USE issue #25
+1E4EC..1E4EF ; Top # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH # 1E4EE is below, but made to for ccc
# ================================================
# Indic_Positional_Category=Top_And_Right
-0E33 ; Top_And_Right # Lo THAI CHARACTER SARA AM # IMC has Right, which seems to be a mistake.
-0EB3 ; Top_And_Right # Lo LAO VOWEL SIGN AM # IMC has Right, which seems to be a mistake.
+0E33 ; Top_And_Right # Lo THAI CHARACTER SARA AM # IPC has Right, which seems to be a mistake.
+0EB3 ; Top_And_Right # Lo LAO VOWEL SIGN AM # IPC has Right, which seems to be a mistake.
# ================================================
# ================================================
@@ -72,6 +79,9 @@ AA35   ; Top # Mn       CHAM CONSONANT SIGN
16F4F ; Bottom # Mn MIAO SIGN CONSONANT MODIFIER BAR
16F51..16F87 ; Bottom # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
16F8F..16F92 ; Bottom # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+#HIEROGLYPHS defined here while ISC is being used as a proxy for dedicated Hieroglyph cluster
+13440 ; Bottom # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+13447..13455 ; Bottom # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
# ================================================
@@ -84,6 +94,7 @@ AA35   ; Top # Mn       CHAM CONSONANT SIGN
07EB..07F3 ; Top # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
07FD ; Top # Mn NKO DANTAYALAN # Not really top, but assigned here to allow ccc to control mark order
1885..1886 ; Top # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1CF8..1CF9 ; Top # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
10D24..10D27 ; Top # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
10EAB..10EAC ; Top # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
16B30..16B36 ; Top # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
diff --git a/src/ms-use/IndicShapingInvalidCluster.txt b/src/ms-use/IndicShapingInvalidCluster.txt
index c4efe1472..9e0edd34c 100644
--- a/src/ms-use/IndicShapingInvalidCluster.txt
+++ b/src/ms-use/IndicShapingInvalidCluster.txt
@@ -8,98 +8,106 @@
#
# Scope: This file enumerates sequences of characters that should be treated as invalid clusters
- 0905 0946 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E
- 0905 093E ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA
- 0930 094D 0907 ; # DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I
- 0909 0941 ; # DEVANAGARI LETTER U, DEVANAGARI VOWEL SIGN U
- 090F 0945 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN CANDRA E
- 090F 0946 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E
- 090F 0947 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN E
- 0905 0949 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA O
- 0906 0945 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN CANDRA E
- 0905 094A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT O
- 0906 0946 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN SHORT E
- 0905 094B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN O
- 0906 0947 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN E
- 0905 094C ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AU
- 0906 0948 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN AI
- 0905 0945 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA E
- 0905 093A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE
- 0905 093B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OOE
- 0906 093A ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN OE
- 0905 094F ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW
- 0905 0956 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UE
- 0905 0957 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UUE
- 0985 09BE ; # BENGALI LETTER A, BENGALI VOWEL SIGN AA
- 098B 09C3 ; # BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R
- 098C 09E2 ; # BENGALI LETTER VOCALIC L, BENGALI VOWEL SIGN VOCALIC L
- 0A05 0A3E ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA
- 0A72 0A3F ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN I
- 0A72 0A40 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN II
- 0A73 0A41 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN U
- 0A73 0A42 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN UU
- 0A72 0A47 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN EE
- 0A05 0A48 ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AI
- 0A73 0A4B ; # GURMUKHI URA, GURMUKHI VOWEL SIGN OO
- 0A05 0A4C ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU
- 0A85 0ABE ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA
- 0A85 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E
- 0A85 0AC7 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN E
- 0A85 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AI
- 0A85 0AC9 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA O
- 0A85 0ACB ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN O
- 0A85 0ABE 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E
- 0A85 0ACC ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AU
- 0A85 0ABE 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI
- 0AC5 0ABE ; # GUJARATI VOWEL SIGN CANDRA E, GUJARATI VOWEL SIGN AA
- 0B05 0B3E ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA
- 0B0F 0B57 ; # ORIYA LETTER E, ORIYA AU LENGTH MARK
- 0B13 0B57 ; # ORIYA LETTER O, ORIYA AU LENGTH MARK
- 0B85 0BC2 ; # TAMIL LETTER A, TAMIL VOWEL SIGN UU
- 0C12 0C55 ; # TELUGU LETTER O, TELUGU LENGTH MARK
- 0C12 0C4C ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU
- 0C3F 0C55 ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK
- 0C46 0C55 ; # TELUGU VOWEL SIGN E, TELUGU LENGTH MARK
- 0C4A 0C55 ; # TELUGU VOWEL SIGN O, TELUGU LENGTH MARK
- 0C89 0CBE ; # KANNADA LETTER U, KANNADA VOWEL SIGN AA
- 0C92 0CCC ; # KANNADA LETTER O, KANNADA VOWEL SIGN AU
- 0C8B 0CBE ; # KANNADA LETTER VOCALIC R, KANNADA VOWEL SIGN AA
- 0D07 0D57 ; # MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK
- 0D09 0D57 ; # MALAYALAM LETTER U, MALAYALAM AU LENGTH MARK
- 0D0E 0D46 ; # MALAYALAM LETTER E, MALAYALAM VOWEL SIGN E
- 0D12 0D3E ; # MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA
- 0D12 0D57 ; # MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK
- 0D85 0DCF ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN AELA-PILLA
- 0D85 0DD0 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN KETTI AEDA-PILLA
- 0D85 0DD1 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN DIGA AEDA-PILLA
- 0D8B 0DDF ; # SINHALA LETTER UYANNA, SINHALA VOWEL SIGN GAYANUKITTA
- 0D8D 0DD8 ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA
- 0D8F 0DDF ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA
- 0D91 0DCA ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA
- 0D91 0DD9 ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA
- 0D91 0DDA ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA
- 0D91 0DDC ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA
- 0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
- 0D91 0DDE ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
- 0D94 0DDF ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA
- 11005 11038 ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA
- 1100B 1103E ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R
- 1100F 11042 ; # BRAHMI LETTER E, BRAHMI VOWEL SIGN E
- 11680 116AD ; # TAKRI LETTER A, TAKRI VOWEL SIGN AA
- 11686 116B2 ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
- 11680 116B4 ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
- 11680 116B5 ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
- 112B0 112E0 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
- 112B0 112E5 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
- 112B0 112E6 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
- 112B0 112E7 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN O
- 112B0 112E8 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AU
- 11481 114B0 ; # TIRHUTA LETTER A, TIRHUTA VOWEL SIGN AA
- 114AA 114B5 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC R
- 114AA 114B6 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC RR
- 1148B 114BA ; # TIRHUTA LETTER E, TIRHUTA VOWEL SIGN SHORT E
- 1148D 114BA ; # TIRHUTA LETTER O, TIRHUTA VOWEL SIGN SHORT E
- 11600 11639 ; # MODI LETTER A, MODI VOWEL SIGN E
- 11600 1163A ; # MODI LETTER A, MODI VOWEL SIGN AI
- 11601 11639 ; # MODI LETTER AA, MODI VOWEL SIGN E
- 11601 1163A ; # MODI LETTER AA, MODI VOWEL SIGN AI
+ 0905 0946 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E
+ 0905 093E ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA
+ 0930 094D 0907 ; # DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I
+ 0909 0941 ; # DEVANAGARI LETTER U, DEVANAGARI VOWEL SIGN U
+ 090F 0945 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN CANDRA E
+ 090F 0946 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E
+ 090F 0947 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN E
+ 0905 0949 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA O
+ 0906 0945 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN CANDRA E
+ 0905 094A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT O
+ 0906 0946 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN SHORT E
+ 0905 094B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN O
+ 0906 0947 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN E
+ 0905 094C ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AU
+ 0906 0948 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN AI
+ 0905 0945 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA E
+ 0905 093A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE
+ 0905 093B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OOE
+ 0906 093A ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN OE
+ 0905 094F ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW
+ 0905 0956 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UE
+ 0905 0957 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UUE
+ 0985 09BE ; # BENGALI LETTER A, BENGALI VOWEL SIGN AA
+ 098B 09C3 ; # BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R
+ 098C 09E2 ; # BENGALI LETTER VOCALIC L, BENGALI VOWEL SIGN VOCALIC L
+ 0A05 0A3E ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA
+ 0A72 0A3F ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN I
+ 0A72 0A40 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN II
+ 0A73 0A41 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN U
+ 0A73 0A42 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN UU
+ 0A72 0A47 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN EE
+ 0A05 0A48 ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AI
+ 0A73 0A4B ; # GURMUKHI URA, GURMUKHI VOWEL SIGN OO
+ 0A05 0A4C ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU
+ 0A85 0ABE ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA
+ 0A85 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E
+ 0A85 0AC7 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN E
+ 0A85 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AI
+ 0A85 0AC9 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA O
+ 0A85 0ACB ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN O
+ 0A85 0ABE 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E
+ 0A85 0ACC ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AU
+ 0A85 0ABE 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI
+ 0AC5 0ABE ; # GUJARATI VOWEL SIGN CANDRA E, GUJARATI VOWEL SIGN AA
+ 0B05 0B3E ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA
+ 0B0F 0B57 ; # ORIYA LETTER E, ORIYA AU LENGTH MARK
+ 0B13 0B57 ; # ORIYA LETTER O, ORIYA AU LENGTH MARK
+ 0B85 0BC2 ; # TAMIL LETTER A, TAMIL VOWEL SIGN UU
+ 0C12 0C55 ; # TELUGU LETTER O, TELUGU LENGTH MARK
+ 0C12 0C4C ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU
+ 0C3F 0C55 ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK
+ 0C46 0C55 ; # TELUGU VOWEL SIGN E, TELUGU LENGTH MARK
+ 0C4A 0C55 ; # TELUGU VOWEL SIGN O, TELUGU LENGTH MARK
+ 0C89 0CBE ; # KANNADA LETTER U, KANNADA VOWEL SIGN AA
+ 0C92 0CCC ; # KANNADA LETTER O, KANNADA VOWEL SIGN AU
+ 0C8B 0CBE ; # KANNADA LETTER VOCALIC R, KANNADA VOWEL SIGN AA
+ 0D07 0D57 ; # MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK
+ 0D09 0D57 ; # MALAYALAM LETTER U, MALAYALAM AU LENGTH MARK
+ 0D0E 0D46 ; # MALAYALAM LETTER E, MALAYALAM VOWEL SIGN E
+ 0D12 0D3E ; # MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA
+ 0D12 0D57 ; # MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK
+ 0D85 0DCF ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN AELA-PILLA
+ 0D85 0DD0 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN KETTI AEDA-PILLA
+ 0D85 0DD1 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ 0D8B 0DDF ; # SINHALA LETTER UYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+ 0D8D 0DD8 ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA
+ 0D8F 0DDF ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+ 0D91 0DCA ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA
+ 0D91 0DD9 ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA
+ 0D91 0DDA ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA
+ 0D91 0DDC ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA
+ 0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
+ 0D91 0DDE ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+ 0D94 0DDF ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+ 11005 11038 ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA
+ 1100B 1103E ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R
+ 1100F 11042 ; # BRAHMI LETTER E, BRAHMI VOWEL SIGN E
+ 11680 116AD ; # TAKRI LETTER A, TAKRI VOWEL SIGN AA
+ 11686 116B2 ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
+ 11680 116B4 ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
+ 11680 116B5 ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
+ 11200 1122C ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AA
+ 11240 1122E ; # KHOJKI LETTER SHORT I, KHOJKI VOWEL SIGN II
+ 11206 1122C ; # KHOJKI LETTER O, KHOJKI VOWEL SIGN AA
+ 11200 11231 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AI
+ 11200 11233 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AU
+ 11200 1122C 11231 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN AI
+ 1122C 11230 ; # KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN E
+ 1122C 11231 ; # KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN AI
+ 112B0 112E0 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
+ 112B0 112E5 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
+ 112B0 112E6 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
+ 112B0 112E7 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN O
+ 112B0 112E8 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AU
+ 11481 114B0 ; # TIRHUTA LETTER A, TIRHUTA VOWEL SIGN AA
+ 114AA 114B5 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC R
+ 114AA 114B6 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC RR
+ 1148B 114BA ; # TIRHUTA LETTER E, TIRHUTA VOWEL SIGN SHORT E
+ 1148D 114BA ; # TIRHUTA LETTER O, TIRHUTA VOWEL SIGN SHORT E
+ 11600 11639 ; # MODI LETTER A, MODI VOWEL SIGN E
+ 11600 1163A ; # MODI LETTER A, MODI VOWEL SIGN AI
+ 11601 11639 ; # MODI LETTER AA, MODI VOWEL SIGN E
+ 11601 1163A ; # MODI LETTER AA, MODI VOWEL SIGN AI
diff --git a/src/ms-use/IndicSyllabicCategory-Additional.txt b/src/ms-use/IndicSyllabicCategory-Additional.txt
index 8bcada38a..0ca2aad10 100644
--- a/src/ms-use/IndicSyllabicCategory-Additional.txt
+++ b/src/ms-use/IndicSyllabicCategory-Additional.txt
@@ -5,6 +5,7 @@
# Updated for Unicode 12.1 by Andrew Glass 2019-05-24
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
# Updated for Unicode 14.0 by Andrew Glass 2021-09-25
+# Updated for Unicode 15.0 by Andrew Glass 2022-09-16
# ================================================
# OVERRIDES TO ASSIGNED VALUES
@@ -18,23 +19,13 @@ AA29 ; Bindu # Mn  CHAM VOWEL SIGN AA
# ================================================
# Indic_Syllabic_Category=Consonant
-0840..0858 ; Consonant # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
-0F00..0F01 ; Consonant # Lo [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED
-0F04..0F06 ; Consonant # Po TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA
19C1..19C7 ; Consonant # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B # Reassigned to avoid clustering with a base consonant
-25CC ; Consonant # So DOTTED CIRCLE
+25CC ; Consonant # So DOTTED CIRCLE #Reassigned to allow it to cluster as a generic base
# ================================================
# Indic_Syllabic_Category=Consonant_Dead
-0F7F ; Consonant_Dead # Mc TIBETAN SIGN RNAM BCAD # reassigned so that visarga will form an independent cluster
-
-# ================================================
-
-# Indic_Syllabic_Category=Consonant_Final
-0F35 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
-0F37 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
-0FC6 ; Consonant_Final # Mn TIBETAN SYMBOL PADMA GDAN
+0F7F ; Consonant_Dead # Mc TIBETAN SIGN RNAM BCAD # reassigned so that visarga can form an independent cluster, but see #19
# ================================================
@@ -49,8 +40,8 @@ AA29 ; Bindu # Mn  CHAM VOWEL SIGN AA
# ================================================
# Indic_Syllabic_Category=Nukta
-0F71 ; Nukta # Mn TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel
-10A38..10A3A ; Nukta # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+0F71 ; Nukta # Mn TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel, but see #22
+1BF2..1BF3 ; Nukta # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN # see USE issue #20
# ================================================
@@ -73,6 +64,9 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
# Indic_Syllabic_Category=Consonant
0800..0815 ; Consonant # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+0840..0858 ; Consonant # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+0F00..0F01 ; Consonant # Lo [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED
+0F04..0F06 ; Consonant # Po TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA
1800 ; Consonant # Po MONGOLIAN BIRGA # Reassigned so that legacy Birga + MFVS sequences still work
1807 ; Consonant # Po MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER
180A ; Consonant # Po MONGOLIAN NIRUGU
@@ -94,11 +88,13 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
10E80..10EA9 ; Consonant # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
10EB0..10EB1 ; Consonant # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
10F30..10F45 ; Consonant # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+10F70..10F81 ; Consonant # Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
111DA ; Consonant # Lo SHARADA EKAM
#HIEROGLYPHS to be moved to new category
-13000..1342E ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+13000..1342F ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
#For the Begin and End segment to be handled fully correctly, the cluster model needs to be modified.
13437..13438 ; Consonant # Lo [2] EGYPTIAN HIEROGLYPH BEGIN SEGMENT..EGYPTIAN HIEROGLYPH END SEGMENT
+13441..13446 ; Consonant # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..HIEROGLYPH WIDE LOST SIGN
16B00..16B2F ; Consonant # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
16F00..16F4A ; Consonant # Lo [75] MIAO LETTER PA..MIAO LETTER RTE
16FE4 ; Consonant # Mn KHITAN SMALL SCRIPT FILLER # Avoids Mn pushing this into VOWEL class
@@ -113,6 +109,8 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
1E14F ; Consonant # So NYIAKENG PUACHUE HMONG CIRCLED CA
1E290..1E2AD ; Consonant # Lo [30] TOTO LETTER PA..TOTO LETTER A
1E2C0..1E2EB ; Consonant # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
+1E4D0..1E4EA ; Consonant # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL
+1E4EB ; Consonant # Lm NAG MUNDARI SIGN OJOD
1E900..1E921 ; Consonant # Lu [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
1E922..1E943 ; Consonant # Ll [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
1E94B ; Consonant # Lm ADLAM NASALIZATION MARK
@@ -140,7 +138,6 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
0F39 ; Nukta # Mn TIBETAN MARK TSA -PHRU # NOW IN UNICODE 10.0
1885..1886 ; Nukta # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
18A9 ; Nukta # Mn MONGOLIAN LETTER ALI GALI DAGALGA
-1B6B..1B73 ; Nukta # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
10AE5..10AE6 ; Nukta # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
16F4F ; Nukta # Mn MIAO SIGN CONSONANT MODIFIER BAR
1BC9D..1BC9E ; Nukta # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
@@ -155,6 +152,7 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
16AC0..16AC9 ; Number # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
1E140..1E149 ; Number # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
1E2F0..1E2F9 ; Number # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+1E4F0..1E4F9 ; Number # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE
1E950..1E959 ; Number # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
# ================================================
@@ -176,7 +174,9 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
# Indic_Syllabic_Category=Virama
2D7F ; Virama # Mn TIFINAGH CONSONANT JOINER
+#HIEROGLYPHS to be moved to new category
13430..13436 ; Virama # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+13439..1343B ; Virama # Cf [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM
# ================================================
@@ -191,6 +191,21 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
0B55 ; Vowel_Dependent # Mn ORIYA SIGN OVERLINE
10EAB..10EAC ; Vowel_Dependent # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
16F51..16F87 ; Vowel_Dependent # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+1E4EC..1E4EF ; Vowel_Dependent # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
+
+# ================================================
+
+# Indic_Syllabic_Category=Cantillation_Mark
+
+1CF8..1CF9 ; Cantillation_Mark # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+#HIEROGLYPHS to be moved to new category
+13440 ; Cantillation_Mark # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+13447..13455 ; Cantillation_Mark # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+
+# ================================================
+
+# Indic_Syllabic_Category=Symbol_Modifier
+1B6B..1B73 ; Symbol_Modifier # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
# ================================================
# ================================================
@@ -198,24 +213,56 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
# ================================================
# ================================================
-# USE_Syllabic_Category=Hieroglyph
-# 13000..1342E ; Hieroglyph # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+# USE, Extended_Syllabic_Category=Hieroglyph
+# 13000..1342F ; Hieroglyph # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
+# 13441..13446 ; Hieroglyph # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..HIEROGLYPH WIDE LOST SIGN
# ================================================
-# USE_Syllabic_Category=Hieroglyph_Joiner
-# 13430..13436 ; Hieroglyph_Joiner # Cf EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+# USE, Extended_Syllabic_Category=Hieroglyph_Joiner
+# 13430..13436 ; Hieroglyph_Joiner # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+# 13439..1343B ; Hieroglyph_Joiner # Cf [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM
# ================================================
-# USE_Syllabic_Category= Hieroglyph_Segment_Begin
+# USE, Extended_Syllabic_Category=Hieroglyph_Mark_Begin
+# 005B ; Hieroglyph_Mark_Begin # Ps LEFT SQUARE BRACKET
+# 007B ; Hieroglyph_Mark_Begin # Ps LEFT CURLY BRACKET
+# 27E6 ; Hieroglyph_Mark_Begin # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+# 27E8 ; Hieroglyph_Mark_Begin # Ps MATHEMATICAL LEFT ANGLE BRACKET
+# 2E22 ; Hieroglyph_Mark_Begin # Ps TOP LEFT HALF BRACKET
+# 2E24 ; Hieroglyph_Mark_Begin # Ps BOTTOM LEFT HALF BRACKET
+
+# ================================================
+
+# USE, Extended_Syllabic_Category=Hieroglyph_Mark_End
+# 005D ; Hieroglyph_Mark_Begin # Pe RIGHT SQUARE BRACKET
+# 007D ; Hieroglyph_Mark_Begin # Pe RIGHT CURLY BRACKET
+# 27E7 ; Hieroglyph_Mark_Begin # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+# 27E9 ; Hieroglyph_Mark_Begin # Pe MATHEMATICAL RIGHT ANGLE BRACKET
+# 2E23 ; Hieroglyph_Mark_Begin # Pe TOP RIGHT HALF BRACKET
+# 2E25 ; Hieroglyph_Mark_Begin # Pe BOTTOM RIGHT HALF BRACKET
+
+# ================================================
+
+# USE, Extended_Syllabic_Category=Hieroglyph_Segment_Begin
# 13437 ; Hieroglyph_Segment_Begin # Cf EGYPTIAN HIEROGLYPH BEGIN SEGMENT
# ================================================
-# USE_Syllabic_Category= Hieroglyph_Segment_End
+# USE, Extended_Syllabic_Category=Hieroglyph_Segment_End
# 13438 ; Hieroglyph_Segment_End # Cf EGYPTIAN HIEROGLYPH END SEGMENT
# ================================================
+# USE, Extended_Syllabic_Category=Hieroglyph_Mirror
+# 13440 ; Hieroglyph_Mirror # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+
+# ================================================
+
+# USE, Extended_Syllabic_Category=Hieroglyph_Modifier
+# 13447..13455 ; Hieroglyph_Modifier # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+
+# ================================================
+
# eof
diff --git a/src/sample.py b/src/sample.py
index fd8504800..5d04e803f 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -2,6 +2,8 @@
import sys
import array
+import gi
+gi.require_version('HarfBuzz', '0.0')
from gi.repository import HarfBuzz as hb
from gi.repository import GLib
diff --git a/src/test-algs.cc b/src/test-algs.cc
index f8b8ff666..450a7c439 100644
--- a/src/test-algs.cc
+++ b/src/test-algs.cc
@@ -26,6 +26,7 @@
#include "hb.hh"
#include "hb-algs.hh"
+#include "hb-set.hh"
static char *
@@ -91,5 +92,19 @@ main (int argc, char **argv)
assert (++hb_inc (x) == 3);
assert (x == 3);
+ hb_set_t set1 {1};
+ hb_set_t set2 {2};
+
+ assert (hb_hash (set1) != hb_hash (set2));
+ assert (hb_hash (set1) == hb_hash (hb_set_t {1}));
+ assert (hb_hash (set1) != hb_hash (hb_set_t {}));
+ assert (hb_hash (set1) != hb_hash (hb_set_t {2}));
+ assert (hb_hash (set2) == hb_hash (hb_set_t {2}));
+
+ /* hb_hash, unlike std::hash, dereferences pointers. */
+ assert (hb_hash (set1) == hb_hash (&set1));
+ assert (hb_hash (set1) == hb_hash (hb::shared_ptr<hb_set_t> {hb_set_reference (&set1)}));
+ assert (hb_hash (set1) == hb_hash (hb::unique_ptr<hb_set_t> {hb_set_reference (&set1)}));
+
return 0;
}
diff --git a/src/test-array.cc b/src/test-array.cc
index 6c888138e..28cd02364 100644
--- a/src/test-array.cc
+++ b/src/test-array.cc
@@ -70,6 +70,9 @@ test_reverse_invalid ()
int
main (int argc, char **argv)
{
+ /* The following fails on MSVC. */
+ // assert (sizeof (hb_array_t<int>) == sizeof (hb_sorted_array_t<int>));
+
test_reverse ();
test_reverse_range ();
test_reverse_invalid ();
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index 8d5a69427..8a887922b 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -43,10 +43,8 @@ main (int argc, char **argv)
#ifndef HB_NO_BUFFER_SERIALIZE
- if (argc != 2) {
- fprintf (stderr, "usage: %s font-file\n", argv[0]);
- exit (1);
- }
+ if (argc < 2)
+ argv[1] = (char *) "/dev/null";
hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
@@ -58,7 +56,7 @@ main (int argc, char **argv)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
hb_font_set_scale (font, upem, upem);
- hb_ot_font_set_funcs (font);
+ //hb_ot_font_set_funcs (font);
#ifdef HAVE_FREETYPE
//hb_ft_font_set_funcs (font);
#endif
@@ -75,15 +73,15 @@ main (int argc, char **argv)
while (hb_buffer_deserialize_glyphs (buf,
p, -1, &p,
font,
- HB_BUFFER_SERIALIZE_FORMAT_JSON))
+ HB_BUFFER_SERIALIZE_FORMAT_TEXT))
;
if (*p && *p != '\n')
ret = false;
hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
out, sizeof (out), nullptr,
- font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
- HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+ font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+ HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS);
puts (out);
}
diff --git a/src/test-iter.cc b/src/test-iter.cc
index fd201c85e..bb966d4c9 100644
--- a/src/test-iter.cc
+++ b/src/test-iter.cc
@@ -31,7 +31,6 @@
#include "hb-set.hh"
#include "hb-ot-layout-common.hh"
-
template <typename T>
struct array_iter_t : hb_iter_with_fallback_t<array_iter_t<T>, T&>
{
@@ -114,6 +113,78 @@ test_iterable (const Iterable &lst = Null (Iterable))
test_iterator (lst.iter ());
}
+template <typename It>
+static void check_sequential (It it)
+{
+ int i = 1;
+ for (int v : +it) {
+ assert (v == i++);
+ }
+}
+
+static void test_concat ()
+{
+ hb_vector_t<int> a = {1, 2, 3};
+ hb_vector_t<int> b = {4, 5};
+
+ hb_vector_t<int> c = {};
+ hb_vector_t<int> d = {1, 2, 3, 4, 5};
+
+ auto it1 = hb_concat (a, b);
+ assert (it1.len () == 5);
+ assert (it1.is_random_access_iterator);
+ auto it2 = hb_concat (c, d);
+ assert (it2.len () == 5);
+ auto it3 = hb_concat (d, c);
+ assert (it3.len () == 5);
+ for (int i = 0; i < 5; i++) {
+ assert(it1[i] == i + 1);
+ assert(it2[i] == i + 1);
+ assert(it3[i] == i + 1);
+ }
+
+ check_sequential (it1);
+ check_sequential (it2);
+ check_sequential (it3);
+
+ auto it4 = +it1;
+ it4 += 0;
+ assert (*it4 == 1);
+
+ it4 += 2;
+ assert (*it4 == 3);
+ assert (it4);
+ assert (it4.len () == 3);
+
+ it4 += 2;
+ assert (*it4 == 5);
+ assert (it4);
+ assert (it4.len () == 1);
+
+ it4++;
+ assert (!it4);
+ assert (it4.len () == 0);
+
+ auto it5 = +it1;
+ it5 += 3;
+ assert (*it5 == 4);
+
+ hb_set_t s_a = {1, 2, 3};
+ hb_set_t s_b = {4, 5};
+ auto it6 = hb_concat (s_a, s_b);
+ assert (!it6.is_random_access_iterator);
+ check_sequential (it6);
+ assert (it6.len () == 5);
+
+ it6 += 0;
+ assert (*it6 == 1);
+
+ it6 += 3;
+ assert (*it6 == 4);
+ assert (it6);
+ assert (it6.len () == 2);
+}
+
int
main (int argc, char **argv)
{
@@ -154,7 +225,7 @@ main (int argc, char **argv)
test_iterable<hb_sorted_array_t<const int>> ();
test_iterable<hb_vector_t<float>> ();
test_iterable<hb_set_t> ();
- test_iterable<OT::Coverage> ();
+ test_iterable<OT::Array16Of<OT::HBUINT16>> ();
test_iterator (hb_zip (st, v));
test_iterator_non_default_constructable (hb_enumerate (st));
@@ -248,13 +319,36 @@ main (int argc, char **argv)
;
/* The result should be something like 0->10, 1->11, ..., 9->19 */
assert (hb_map_get (result, 9) == 19);
+ hb_map_destroy (result);
+
+ /* Like above, but passing hb_set_t instead of hb_set_t * */
+ temp1 = 10;
+ temp2 = 0;
+ result =
+ + hb_iter (src)
+ | hb_map ([&] (int i) -> hb_set_t
+ {
+ hb_set_t set;
+ for (unsigned int i = 0; i < temp1; ++i)
+ hb_set_add (&set, i);
+ temp1++;
+ return set;
+ })
+ | hb_reduce ([&] (hb_map_t *acc, hb_set_t value) -> hb_map_t *
+ {
+ hb_map_set (acc, temp2++, hb_set_get_population (&value));
+ return acc;
+ }, hb_map_create ())
+ ;
+ /* The result should be something like 0->10, 1->11, ..., 9->19 */
+ assert (hb_map_get (result, 9) == 19);
+ hb_map_destroy (result);
unsigned int temp3 = 0;
+ hb_iter(src)
| hb_map([&] (int i) { return ++temp3; })
| hb_reduce([&] (float acc, int value) { return acc + value; }, 0)
;
- hb_map_destroy (result);
+ hb_iter (src)
| hb_drain
@@ -282,5 +376,7 @@ main (int argc, char **argv)
assert (hb_range (-2, -8, -3).len () == 2);
assert (hb_range (-2, -7, -3).len () == 2);
+ test_concat ();
+
return 0;
}
diff --git a/src/test-machinery.cc b/src/test-machinery.cc
new file mode 100644
index 000000000..7fc9c24b5
--- /dev/null
+++ b/src/test-machinery.cc
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#include "hb.hh"
+#include "hb-machinery.hh"
+
+struct hb_intp_lazy_loader_t : hb_lazy_loader_t<int, hb_intp_lazy_loader_t>
+{
+ static int* create () { return nullptr; }
+ static void destroy (int* l) {}
+ static int* get_null () { return nullptr; }
+};
+
+struct hb_void_lazy_loader_t : hb_lazy_loader_t<void, hb_void_lazy_loader_t>
+{
+ static void* create () { return nullptr; }
+ static void destroy (void* l) {}
+ static void* get_null () { return nullptr; }
+};
+
+int
+main (int argc, char **argv)
+{
+ return 0;
+}
diff --git a/src/test-map.cc b/src/test-map.cc
index 5761cc8d6..da77a2f6c 100644
--- a/src/test-map.cc
+++ b/src/test-map.cc
@@ -20,12 +20,12 @@
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
*/
#include "hb.hh"
#include "hb-map.hh"
-
+#include "hb-set.hh"
+#include <string>
int
main (int argc, char **argv)
@@ -55,13 +55,21 @@ main (int argc, char **argv)
/* Test move constructor. */
{
- hb_map_t v {hb_map_t {}};
+ hb_map_t s {};
+ s.set (1, 2);
+ hb_map_t v (std::move (s));
+ assert (s.get_population () == 0);
+ assert (v.get_population () == 1);
}
/* Test move assignment. */
{
+ hb_map_t s {};
+ s.set (1, 2);
hb_map_t v;
- v = hb_map_t {};
+ v = std::move (s);
+ assert (s.get_population () == 0);
+ assert (v.get_population () == 1);
}
/* Test initializing from iterable. */
@@ -71,9 +79,23 @@ main (int argc, char **argv)
s.set (1, 2);
s.set (3, 4);
- hb_map_t v (s);
+ hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> v (s);
+ hb_map_t v0 (v);
+ hb_map_t v1 (s);
+ hb_map_t v2 (std::move (s));
- assert (v.get_population () == 2);
+ assert (s.get_population () == 0);
+ assert (v0.get_population () == 2);
+ assert (v1.get_population () == 2);
+ assert (v2.get_population () == 2);
+ }
+
+ /* Test call fini() twice. */
+ {
+ hb_map_t s;
+ for (int i = 0; i < 16; i++)
+ s.set(i, i+1);
+ s.fini();
}
/* Test initializing from iterator. */
@@ -98,5 +120,187 @@ main (int argc, char **argv)
assert (v2.get_population () == 2);
}
+ /* Test class key / value types. */
+ {
+ hb_hashmap_t<hb_bytes_t, int> m1;
+ hb_hashmap_t<int, hb_bytes_t> m2;
+ hb_hashmap_t<hb_bytes_t, hb_bytes_t> m3;
+ assert (m1.get_population () == 0);
+ assert (m2.get_population () == 0);
+ assert (m3.get_population () == 0);
+ }
+
+ {
+ hb_hashmap_t<int, int> m0;
+ hb_hashmap_t<std::string, int> m1;
+ hb_hashmap_t<int, std::string> m2;
+ hb_hashmap_t<std::string, std::string> m3;
+
+ std::string s;
+ for (unsigned i = 1; i < 1000; i++)
+ {
+ s += "x";
+ m0.set (i, i);
+ m1.set (s, i);
+ m2.set (i, s);
+ m3.set (s, s);
+ }
+ }
+
+ /* Test hashing maps. */
+ {
+ using pair = hb_pair_t<hb_codepoint_t, hb_codepoint_t>;
+
+ hb_hashmap_t<hb_map_t, hb_map_t> m1;
+
+ m1.set (hb_map_t (), hb_map_t {});
+ m1.set (hb_map_t (), hb_map_t {pair (1u, 2u)});
+ m1.set (hb_map_t {pair (1u, 2u)}, hb_map_t {pair (2u, 3u)});
+
+ assert (m1.get (hb_map_t ()) == hb_map_t {pair (1u, 2u)});
+ assert (m1.get (hb_map_t {pair (1u, 2u)}) == hb_map_t {pair (2u, 3u)});
+ }
+
+ /* Test hashing sets. */
+ {
+ hb_hashmap_t<hb_set_t, hb_set_t> m1;
+
+ m1.set (hb_set_t (), hb_set_t ());
+ m1.set (hb_set_t (), hb_set_t {1});
+ m1.set (hb_set_t {1, 1000}, hb_set_t {2});
+
+ assert (m1.get (hb_set_t ()) == hb_set_t {1});
+ assert (m1.get (hb_set_t {1000, 1}) == hb_set_t {2});
+ }
+
+ /* Test hashing vectors. */
+ {
+ using vector_t = hb_vector_t<unsigned>;
+
+ hb_hashmap_t<vector_t, vector_t> m1;
+
+ m1.set (vector_t (), vector_t {1});
+ m1.set (vector_t {1}, vector_t {2});
+
+ m1 << hb_pair_t<vector_t, vector_t> {vector_t {2}, vector_t ()};
+
+ assert (m1.get (vector_t ()) == vector_t {1});
+ assert (m1.get (vector_t {1}) == vector_t {2});
+ }
+
+ /* Test moving values */
+ {
+ using vector_t = hb_vector_t<unsigned>;
+
+ hb_hashmap_t<vector_t, vector_t> m1;
+ vector_t v {3};
+ assert (v.length == 1);
+ m1 << hb_pair_t<vector_t, vector_t> {vector_t {3}, v};
+ assert (v.length == 1);
+ m1 << hb_pair_t<vector_t, vector_t&&> {vector_t {4}, std::move (v)};
+ assert (v.length == 0);
+ m1 << hb_pair_t<vector_t&&, vector_t> {vector_t {4}, vector_t {5}};
+ m1 << hb_pair_t<vector_t&&, vector_t&&> {vector_t {4}, vector_t {5}};
+
+ hb_hashmap_t<vector_t, vector_t> m2;
+ vector_t v2 {3};
+ m2.set (vector_t {4}, v2);
+ assert (v2.length == 1);
+ m2.set (vector_t {5}, std::move (v2));
+ assert (v2.length == 0);
+ }
+
+ /* Test hb::shared_ptr. */
+ {
+ hb_hashmap_t<hb::shared_ptr<hb_set_t>, hb::shared_ptr<hb_set_t>> m;
+
+ m.set (hb::shared_ptr<hb_set_t> (hb_set_get_empty ()),
+ hb::shared_ptr<hb_set_t> (hb_set_get_empty ()));
+ m.get (hb::shared_ptr<hb_set_t> (hb_set_get_empty ()));
+ m.iter ();
+ m.keys ();
+ m.values ();
+ m.iter_ref ();
+ m.keys_ref ();
+ m.values_ref ();
+ }
+ /* Test hb::unique_ptr. */
+ {
+ hb_hashmap_t<hb::unique_ptr<hb_set_t>, hb::unique_ptr<hb_set_t>> m;
+
+ m.set (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()),
+ hb::unique_ptr<hb_set_t> (hb_set_get_empty ()));
+ m.get (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()));
+ hb::unique_ptr<hb_set_t> *v;
+ m.has (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()), &v);
+ m.iter_ref ();
+ m.keys_ref ();
+ m.values_ref ();
+ }
+ /* Test more complex unique_ptr's. */
+ {
+ hb_hashmap_t<int, hb::unique_ptr<hb_hashmap_t<int, int>>> m;
+
+ m.get (0);
+ const hb::unique_ptr<hb_hashmap_t<int, int>> *v1;
+ m.has (0, &v1);
+ hb::unique_ptr<hb_hashmap_t<int, int>> *v2;
+ m.has (0, &v2);
+ }
+ /* Test hashmap with complex shared_ptrs as keys. */
+ {
+ hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> m;
+
+ hb_map_t *m1 = hb_map_create ();
+ hb_map_t *m2 = hb_map_create ();
+ m1->set (1,3);
+ m2->set (1,3);
+
+ hb::shared_ptr<hb_map_t> p1 {m1};
+ hb::shared_ptr<hb_map_t> p2 {m2};
+ m.set (p1,1);
+
+ assert (m.has (p2));
+
+ m1->set (2,4);
+ assert (!m.has (p2));
+ }
+ /* Test value type with hb_bytes_t. */
+ {
+ hb_hashmap_t<int, hb_bytes_t> m;
+ char c_str[] = "Test";
+ hb_bytes_t bytes (c_str);
+
+ m.set (1, bytes);
+ assert (m.has (1));
+ }
+ /* Test operators. */
+ {
+ hb_map_t m1, m2, m3;
+ m1.set (1, 2);
+ m1.set (2, 4);
+ m2.set (1, 2);
+ m2.set (2, 4);
+ m3.set (1, 3);
+ m3.set (3, 5);
+
+ assert (m1 == m2);
+ assert (m1 != m3);
+ assert (!(m2 == m3));
+
+ m2 = m3;
+ assert (m2.has (1));
+ assert (!m2.has (2));
+ assert (m2.has (3));
+
+ assert (m3.has (3));
+ }
+ /* Test reset. */
+ {
+ hb_hashmap_t<int, hb_set_t> m;
+ m.set (1, hb_set_t {1, 2, 3});
+ m.reset ();
+ }
+
return 0;
}
diff --git a/src/test-multimap.cc b/src/test-multimap.cc
new file mode 100644
index 000000000..8cd8f5285
--- /dev/null
+++ b/src/test-multimap.cc
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include "hb.hh"
+#include "hb-multimap.hh"
+
+int
+main (int argc, char **argv)
+{
+ hb_multimap_t m;
+
+ assert (m.get (10).length == 0);
+
+ m.add (10, 11);
+ assert (m.get (10).length == 1);
+
+ m.add (10, 12);
+ assert (m.get (10).length == 2);
+
+ m.add (10, 13);
+ assert (m.get (10).length == 3);
+ assert (m.get (10)[0] == 11);
+ assert (m.get (10)[1] == 12);
+ assert (m.get (10)[2] == 13);
+
+ assert (m.get (11).length == 0);
+ m.add (11, 14);
+ assert (m.get (10).length == 3);
+ assert (m.get (11).length == 1);
+ assert (m.get (12).length == 0);
+ assert (m.get (10)[0] == 11);
+ assert (m.get (10)[1] == 12);
+ assert (m.get (10)[2] == 13);
+ assert (m.get (11)[0] == 14);
+ assert (m.get (12)[0] == 0); // Array fallback value
+
+ return 0;
+}
diff --git a/src/test-ot-glyphname.cc b/src/test-ot-glyphname.cc
index 50d023166..ec6e149a5 100644
--- a/src/test-ot-glyphname.cc
+++ b/src/test-ot-glyphname.cc
@@ -85,5 +85,5 @@ main (int argc, char **argv)
hb_font_destroy (font);
hb_face_destroy (face);
- return result;
+ return !result;
}
diff --git a/src/test-priority-queue.cc b/src/test-priority-queue.cc
index fab63acb6..e83d72c7e 100644
--- a/src/test-priority-queue.cc
+++ b/src/test-priority-queue.cc
@@ -73,17 +73,9 @@ test_extract ()
assert (queue.is_empty ());
}
-static void
-test_extract_empty ()
-{
- hb_priority_queue_t queue;
- assert (queue.pop_minimum () == hb_pair (0, 0));
-}
-
int
main (int argc, char **argv)
{
test_insert ();
test_extract ();
- test_extract_empty ();
}
diff --git a/src/test-repacker.cc b/src/test-repacker.cc
index 4df063629..94ff0849a 100644
--- a/src/test-repacker.cc
+++ b/src/test-repacker.cc
@@ -28,17 +28,24 @@
#include "hb-repacker.hh"
#include "hb-open-type.hh"
+#include "graph/serialize.hh"
+
+static void extend (const char* value,
+ unsigned len,
+ hb_serialize_context_t* c)
+{
+ char* obj = c->allocate_size<char> (len);
+ hb_memcpy (obj, value, len);
+}
static void start_object(const char* tag,
unsigned len,
hb_serialize_context_t* c)
{
c->push ();
- char* obj = c->allocate_size<char> (len);
- strncpy (obj, tag, len);
+ extend (tag, len, c);
}
-
static unsigned add_object(const char* tag,
unsigned len,
hb_serialize_context_t* c)
@@ -56,6 +63,14 @@ static void add_offset (unsigned id,
c->add_link (*offset, id);
}
+static void add_24_offset (unsigned id,
+ hb_serialize_context_t* c)
+{
+ OT::Offset24* offset = c->start_embed<OT::Offset24> ();
+ c->extend_min (offset);
+ c->add_link (*offset, id);
+}
+
static void add_wide_offset (unsigned id,
hb_serialize_context_t* c)
{
@@ -64,37 +79,401 @@ static void add_wide_offset (unsigned id,
c->add_link (*offset, id);
}
+static void add_gsubgpos_header (unsigned lookup_list,
+ hb_serialize_context_t* c)
+{
+ char header[] = {
+ 0, 1, // major
+ 0, 0, // minor
+ 0, 0, // script list
+ 0, 0, // feature list
+ };
+
+ start_object (header, 8, c);
+ add_offset (lookup_list, c);
+ c->pop_pack (false);
+}
+
+static unsigned add_lookup_list (const unsigned* lookups,
+ char count,
+ hb_serialize_context_t* c)
+{
+ char lookup_count[] = {0, count};
+ start_object ((char *) &lookup_count, 2, c);
+
+ for (int i = 0; i < count; i++)
+ add_offset (lookups[i], c);
+
+ return c->pop_pack (false);
+}
+
+static void start_lookup (int8_t type,
+ int8_t num_subtables,
+ hb_serialize_context_t* c)
+{
+ char lookup[] = {
+ 0, (char)type, // type
+ 0, 0, // flag
+ 0, (char)num_subtables, // num subtables
+ };
+
+ start_object (lookup, 6, c);
+}
+
+static unsigned finish_lookup (hb_serialize_context_t* c)
+{
+ char filter[] = {0, 0};
+ extend (filter, 2, c);
+ return c->pop_pack (false);
+}
+
+static unsigned add_extension (unsigned child,
+ uint8_t type,
+ hb_serialize_context_t* c)
+{
+ char ext[] = {
+ 0, 1,
+ 0, (char) type,
+ };
+
+ start_object (ext, 4, c);
+ add_wide_offset (child, c);
+
+ return c->pop_pack (false);
+
+}
+
+// Adds coverage table fro [start, end]
+static unsigned add_coverage (unsigned start, unsigned end,
+ hb_serialize_context_t* c)
+{
+ if (end - start == 1)
+ {
+ uint8_t coverage[] = {
+ 0, 1, // format
+ 0, 2, // count
+
+ (uint8_t) ((start >> 8) & 0xFF),
+ (uint8_t) (start & 0xFF), // glyph[0]
+
+ (uint8_t) ((end >> 8) & 0xFF),
+ (uint8_t) (end & 0xFF), // glyph[1]
+ };
+ return add_object ((char*) coverage, 8, c);
+ }
+
+ uint8_t coverage[] = {
+ 0, 2, // format
+ 0, 1, // range count
+
+ (uint8_t) ((start >> 8) & 0xFF),
+ (uint8_t) (start & 0xFF), // start
+
+ (uint8_t) ((end >> 8) & 0xFF),
+ (uint8_t) (end & 0xFF), // end
+
+ 0, 0,
+ };
+ return add_object ((char*) coverage, 10, c);
+}
+
+
+template<typename It>
+static unsigned add_coverage (It it,
+ hb_serialize_context_t* c)
+{
+ c->push ();
+ OT::Layout::Common::Coverage_serialize (c, it);
+ return c->pop_pack (false);
+}
+
+// Adds a class that maps glyphs from [start_glyph, end_glyph)
+// to classes 1...n
+static unsigned add_class_def (uint16_t start_glyph,
+ uint16_t end_glyph,
+ hb_serialize_context_t* c)
+{
+ unsigned count = end_glyph - start_glyph;
+ uint8_t header[] = {
+ 0, 1, // format
+
+ (uint8_t) ((start_glyph >> 8) & 0xFF),
+ (uint8_t) (start_glyph & 0xFF), // start_glyph
+
+ (uint8_t) ((count >> 8) & 0xFF),
+ (uint8_t) (count & 0xFF), // count
+ };
+
+ start_object ((char*) header, 6, c);
+ for (uint16_t i = 1; i <= count; i++)
+ {
+ uint8_t class_value[] = {
+ (uint8_t) ((i >> 8) & 0xFF),
+ (uint8_t) (i & 0xFF), // count
+ };
+ extend ((char*) class_value, 2, c);
+ }
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_1 (unsigned* pair_sets,
+ char count,
+ unsigned coverage,
+ hb_serialize_context_t* c)
+{
+ char format[] = {
+ 0, 1
+ };
+
+ start_object (format, 2, c);
+ add_offset (coverage, c);
+
+ char value_format[] = {
+ 0, 0,
+ 0, 0,
+ 0, count,
+ };
+ extend (value_format, 6, c);
+
+ for (char i = 0; i < count; i++)
+ add_offset (pair_sets[(unsigned) i], c);
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_2 (unsigned starting_class,
+ unsigned coverage,
+ unsigned class_def_1, uint16_t class_def_1_count,
+ unsigned class_def_2, uint16_t class_def_2_count,
+ unsigned* device_tables,
+ hb_serialize_context_t* c)
+{
+ uint8_t format[] = {
+ 0, 2
+ };
+
+ start_object ((char*) format, 2, c);
+ add_offset (coverage, c);
+
+ unsigned num_values = 4;
+ uint8_t format1 = 0x01 | 0x02 | 0x08;
+ uint8_t format2 = 0x04;
+ if (device_tables) {
+ format2 |= 0x20;
+ num_values += 1;
+ }
+ uint8_t value_format[] = {
+ 0, format1,
+ 0, format2,
+ };
+
+ extend ((char*) value_format, 4, c);
+
+ add_offset (class_def_1, c);
+ add_offset (class_def_2, c);
+
+ uint8_t class_counts[] = {
+ (uint8_t) ((class_def_1_count >> 8) & 0xFF),
+ (uint8_t) (class_def_1_count & 0xFF),
+ (uint8_t) ((class_def_2_count >> 8) & 0xFF),
+ (uint8_t) (class_def_2_count & 0xFF),
+ };
+ extend ((char*) class_counts, 4, c);
+
+ unsigned num_bytes_per_record = class_def_2_count * num_values * 2;
+ uint8_t* record = (uint8_t*) calloc (1, num_bytes_per_record);
+ int device_index = 0;
+ for (uint16_t i = 0; i < class_def_1_count; i++)
+ {
+
+ for (uint16_t j = 0; j < class_def_2_count; j++)
+ {
+ for (int k = 0; k < 4; k++) {
+ uint8_t value[] = {
+ (uint8_t) (i + starting_class),
+ (uint8_t) (i + starting_class),
+ };
+ extend ((char*) value, 2, c);
+ }
+
+ if (device_tables) {
+ add_offset (device_tables[device_index++], c);
+ }
+ }
+ }
+ free (record);
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_mark_base_pos_1 (unsigned mark_coverage,
+ unsigned base_coverage,
+ unsigned mark_array,
+ unsigned base_array,
+ unsigned class_count,
+ hb_serialize_context_t* c)
+{
+ uint8_t format[] = {
+ 0, 1
+ };
+
+ start_object ((char*) format, 2, c);
+ add_offset (mark_coverage, c);
+ add_offset (base_coverage, c);
+
+ uint8_t count[] = {
+ (uint8_t) ((class_count >> 8) & 0xFF),
+ (uint8_t) (class_count & 0xFF),
+ };
+ extend ((char*) count, 2, c);
+
+ add_offset (mark_array, c);
+ add_offset (base_array, c);
+
+ return c->pop_pack (false);
+}
+
+template<int mark_count,
+ int class_count,
+ int base_count,
+ int table_count>
+struct MarkBasePosBuffers
+{
+ unsigned base_anchors[class_count * base_count];
+ unsigned mark_anchors[mark_count];
+ uint8_t anchor_buffers[class_count * base_count + 100];
+ uint8_t class_buffer[class_count * 2];
+
+ MarkBasePosBuffers(hb_serialize_context_t* c)
+ {
+ for (unsigned i = 0; i < sizeof(anchor_buffers) / 2; i++)
+ {
+ OT::HBUINT16* value = (OT::HBUINT16*) (&anchor_buffers[2*i]);
+ *value = i;
+ }
+
+ for (unsigned i = 0; i < class_count * base_count; i++)
+ {
+ base_anchors[i] = add_object ((char*) &anchor_buffers[i], 100, c);
+ if (i < class_count) {
+ class_buffer[i*2] = (uint8_t) ((i >> 8) & 0xFF);
+ class_buffer[i*2 + 1] = (uint8_t) (i & 0xFF);
+ }
+ }
+
+ for (unsigned i = 0; i < mark_count; i++)
+ {
+ mark_anchors[i] = add_object ((char*) &anchor_buffers[i], 4, c);
+ }
+ }
+
+ unsigned create_mark_base_pos_1 (unsigned table_index, hb_serialize_context_t* c)
+ {
+ unsigned class_per_table = class_count / table_count;
+ unsigned mark_per_class = mark_count / class_count;
+ unsigned start_class = class_per_table * table_index;
+ unsigned end_class = class_per_table * (table_index + 1) - 1;
+
+ // baseArray
+ uint8_t base_count_buffer[] = {
+ (uint8_t) ((base_count >> 8) & 0xFF),
+ (uint8_t) (base_count & 0xFF),
+
+ };
+ start_object ((char*) base_count_buffer, 2, c);
+ for (unsigned base = 0; base < base_count; base++)
+ {
+ for (unsigned klass = start_class; klass <= end_class; klass++)
+ {
+ unsigned i = base * class_count + klass;
+ add_offset (base_anchors[i], c);
+ }
+ }
+ unsigned base_array = c->pop_pack (false);
+
+ // markArray
+ unsigned num_marks = class_per_table * mark_per_class;
+ uint8_t mark_count_buffer[] = {
+ (uint8_t) ((num_marks >> 8) & 0xFF),
+ (uint8_t) (num_marks & 0xFF),
+ };
+ start_object ((char*) mark_count_buffer, 2, c);
+ for (unsigned mark = 0; mark < mark_count; mark++)
+ {
+ unsigned klass = mark % class_count;
+ if (klass < start_class || klass > end_class) continue;
+ klass -= start_class;
+
+ extend ((char*) &class_buffer[2 * klass], 2, c);
+ add_offset (mark_anchors[mark], c);
+ }
+ unsigned mark_array = c->pop_pack (false);
+
+ // markCoverage
+ auto it =
+ + hb_range ((hb_codepoint_t) mark_count)
+ | hb_filter ([&] (hb_codepoint_t mark) {
+ unsigned klass = mark % class_count;
+ return klass >= class_per_table * table_index &&
+ klass < class_per_table * (table_index + 1);
+ })
+ ;
+ unsigned mark_coverage = add_coverage (it, c);
+
+ // baseCoverage
+ unsigned base_coverage = add_coverage (10, 10 + base_count - 1, c);
+
+ return add_mark_base_pos_1 (mark_coverage,
+ base_coverage,
+ mark_array,
+ base_array,
+ class_per_table,
+ c);
+ }
+};
+
+
+
+
+
static void run_resolve_overflow_test (const char* name,
hb_serialize_context_t& overflowing,
hb_serialize_context_t& expected,
- unsigned num_iterations = 0)
+ unsigned num_iterations = 0,
+ bool recalculate_extensions = false,
+ hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B'))
{
printf (">>> Testing overflowing resolution for %s\n",
name);
graph_t graph (overflowing.object_graph ());
-
- unsigned buffer_size = overflowing.end - overflowing.start;
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- assert (overflowing.offset_overflow ());
- hb_resolve_overflows (overflowing.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, num_iterations);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
-
- assert (!expected.offset_overflow ());
- hb_bytes_t expected_result = expected.copy_bytes ();
-
- assert (result.length == expected_result.length);
- for (unsigned i = 0; i < expected_result.length; i++)
+ graph_t expected_graph (expected.object_graph ());
+ if (graph::will_overflow (expected_graph))
{
- assert (result[i] == expected_result[i]);
+ expected_graph.assign_spaces ();
+ expected_graph.sort_shortest_distance ();
}
- result.fini ();
- expected_result.fini ();
- free (out_buffer);
+ // Check that overflow resolution succeeds
+ assert (overflowing.offset_overflow ());
+ assert (hb_resolve_graph_overflows (tag,
+ num_iterations,
+ recalculate_extensions,
+ graph));
+
+ // Check the graphs can be serialized.
+ hb_blob_t* out = graph::serialize (graph);
+ assert (out);
+ hb_blob_destroy (out);
+ out = graph::serialize (expected_graph);
+ assert (out);
+ hb_blob_destroy (out);
+
+ // Check the graphs are equivalent
+ graph.normalize ();
+ expected_graph.normalize ();
+ assert (graph == expected_graph);
}
static void add_virtual_offset (unsigned id,
@@ -139,6 +518,58 @@ populate_serializer_with_overflow (hb_serialize_context_t* c)
}
static void
+populate_serializer_with_priority_overflow (hb_serialize_context_t* c)
+{
+ std::string large_string(50000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_e = add_object ("e", 1, c);
+ unsigned obj_d = add_object ("d", 1, c);
+
+ start_object (large_string.c_str (), 50000, c);
+ add_offset (obj_e, c);
+ unsigned obj_c = c->pop_pack (false);
+
+ start_object (large_string.c_str (), 20000, c);
+ add_offset (obj_d, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_offset (obj_b, c);
+ add_offset (obj_c, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_with_priority_overflow_expected (hb_serialize_context_t* c)
+{
+ std::string large_string(50000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_e = add_object ("e", 1, c);
+
+ start_object (large_string.c_str (), 50000, c);
+ add_offset (obj_e, c);
+ unsigned obj_c = c->pop_pack (false);
+
+ unsigned obj_d = add_object ("d", 1, c);
+
+ start_object (large_string.c_str (), 20000, c);
+ add_offset (obj_d, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_offset (obj_b, c);
+ add_offset (obj_c, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
+}
+
+
+static void
populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
{
std::string large_string(70000, 'a');
@@ -679,26 +1110,6 @@ populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c)
}
static void
-populate_serializer_complex_1 (hb_serialize_context_t* c)
-{
- c->start_serialize<char> ();
-
- unsigned obj_4 = add_object ("jkl", 3, c);
- unsigned obj_3 = add_object ("ghi", 3, c);
-
- start_object ("def", 3, c);
- add_offset (obj_3, c);
- unsigned obj_2 = c->pop_pack (false);
-
- start_object ("abc", 3, c);
- add_offset (obj_2, c);
- add_offset (obj_4, c);
- c->pop_pack (false);
-
- c->end_serialize();
-}
-
-static void
populate_serializer_complex_2 (hb_serialize_context_t* c)
{
c->start_serialize<char> ();
@@ -763,84 +1174,297 @@ populate_serializer_virtual_link (hb_serialize_context_t* c)
start_object ("b", 1, c);
add_offset (obj_d, c);
- unsigned obj_b = c->pop_pack ();
+ unsigned obj_b = c->pop_pack (false);
start_object ("e", 1, c);
add_virtual_offset (obj_b, c);
- unsigned obj_e = c->pop_pack();
+ unsigned obj_e = c->pop_pack (false);
start_object ("c", 1, c);
add_offset (obj_e, c);
- unsigned obj_c = c->pop_pack ();
+ unsigned obj_c = c->pop_pack (false);
start_object ("a", 1, c);
add_offset (obj_b, c);
add_offset (obj_c, c);
- c->pop_pack ();
+ c->pop_pack (false);
c->end_serialize();
}
-static void test_sort_kahn_1 ()
+static void
+populate_serializer_with_24_and_32_bit_offsets (hb_serialize_context_t* c)
{
- size_t buffer_size = 100;
- void* buffer = malloc (buffer_size);
- hb_serialize_context_t c (buffer, buffer_size);
- populate_serializer_complex_1 (&c);
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
- graph_t graph (c.object_graph ());
- graph.sort_kahn ();
+ unsigned obj_f = add_object ("f", 1, c);
+ unsigned obj_g = add_object ("g", 1, c);
+ unsigned obj_j = add_object ("j", 1, c);
+ unsigned obj_k = add_object ("k", 1, c);
+
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_f, c);
+ unsigned obj_c = c->pop_pack (false);
- assert(strncmp (graph.object (3).head, "abc", 3) == 0);
- assert(graph.object (3).links.length == 2);
- assert(graph.object (3).links[0].objidx == 2);
- assert(graph.object (3).links[1].objidx == 1);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_g, c);
+ unsigned obj_d = c->pop_pack (false);
- assert(strncmp (graph.object (2).head, "def", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 0);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_j, c);
+ unsigned obj_h = c->pop_pack (false);
- assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
- assert(graph.object (1).links.length == 0);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_k, c);
+ unsigned obj_i = c->pop_pack (false);
- assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ start_object ("e", 1, c);
+ add_wide_offset (obj_h, c);
+ add_wide_offset (obj_i, c);
+ unsigned obj_e = c->pop_pack (false);
- free (buffer);
+ start_object ("b", 1, c);
+ add_24_offset (obj_c, c);
+ add_24_offset (obj_d, c);
+ add_24_offset (obj_e, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_24_offset (obj_b, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
}
-static void test_sort_kahn_2 ()
+static void
+populate_serializer_with_extension_promotion (hb_serialize_context_t* c,
+ int num_extensions = 0)
{
- size_t buffer_size = 100;
- void* buffer = malloc (buffer_size);
- hb_serialize_context_t c (buffer, buffer_size);
- populate_serializer_complex_2 (&c);
+ constexpr int num_lookups = 5;
+ constexpr int num_subtables = num_lookups * 2;
+ unsigned int lookups[num_lookups];
+ unsigned int subtables[num_subtables];
+ unsigned int extensions[num_subtables];
- graph_t graph (c.object_graph ());
- graph.sort_kahn ();
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
- assert(strncmp (graph.object (4).head, "abc", 3) == 0);
- assert(graph.object (4).links.length == 3);
- assert(graph.object (4).links[0].objidx == 3);
- assert(graph.object (4).links[1].objidx == 0);
- assert(graph.object (4).links[2].objidx == 2);
+ for (int i = num_subtables - 1; i >= 0; i--)
+ subtables[i] = add_object(large_string.c_str (), 15000, c);
- assert(strncmp (graph.object (3).head, "def", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 1);
+ for (int i = num_subtables - 1;
+ i >= (num_lookups - num_extensions) * 2;
+ i--)
+ {
+ unsigned ext_index = i - (num_lookups - num_extensions) * 2;
+ unsigned subtable_index = num_subtables - ext_index - 1;
+ extensions[i] = add_extension (subtables[subtable_index], 5, c);
+ }
- assert(strncmp (graph.object (2).head, "mn", 2) == 0);
- assert(graph.object (2).links.length == 0);
+ for (int i = num_lookups - 1; i >= 0; i--)
+ {
+ bool is_ext = (i >= (num_lookups - num_extensions));
- assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
- assert(graph.object (1).links.length == 1);
- assert(graph.object (1).links[0].objidx == 0);
+ start_lookup (is_ext ? (char) 7 : (char) 5,
+ 2,
+ c);
- assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ if (is_ext) {
+ add_offset (extensions[i * 2], c);
+ add_offset (extensions[i * 2 + 1], c);
+ } else {
+ add_offset (subtables[i * 2], c);
+ add_offset (subtables[i * 2 + 1], c);
+ }
- free (buffer);
+ lookups[i] = finish_lookup (c);
+ }
+
+ unsigned lookup_list = add_lookup_list (lookups, num_lookups, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+}
+
+template<int num_pair_pos_1, int num_pair_set>
+static void
+populate_serializer_with_large_pair_pos_1 (hb_serialize_context_t* c,
+ bool as_extension = false)
+{
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
+
+ constexpr int total_pair_set = num_pair_pos_1 * num_pair_set;
+ unsigned pair_set[total_pair_set];
+ unsigned coverage[num_pair_pos_1];
+ unsigned pair_pos_1[num_pair_pos_1];
+
+ for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+ {
+ for (int j = (i + 1) * num_pair_set - 1; j >= i * num_pair_set; j--)
+ pair_set[j] = add_object (large_string.c_str (), 30000 + j, c);
+
+ coverage[i] = add_coverage (i * num_pair_set,
+ (i + 1) * num_pair_set - 1, c);
+
+ pair_pos_1[i] = add_pair_pos_1 (&pair_set[i * num_pair_set],
+ num_pair_set,
+ coverage[i],
+ c);
+ }
+
+ unsigned pair_pos_2 = add_object (large_string.c_str(), 200, c);
+
+ if (as_extension) {
+ pair_pos_2 = add_extension (pair_pos_2, 2, c);
+ for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+ pair_pos_1[i] = add_extension (pair_pos_1[i], 2, c);
+ }
+
+ start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_1, c);
+
+ for (int i = 0; i < num_pair_pos_1; i++)
+ add_offset (pair_pos_1[i], c);
+ add_offset (pair_pos_2, c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+}
+
+template<int num_pair_pos_2, int num_class_1, int num_class_2>
+static void
+populate_serializer_with_large_pair_pos_2 (hb_serialize_context_t* c,
+ bool as_extension = false,
+ bool with_device_tables = false,
+ bool extra_table = true)
+{
+ std::string large_string(100000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned coverage[num_pair_pos_2];
+ unsigned class_def_1[num_pair_pos_2];
+ unsigned class_def_2[num_pair_pos_2];
+ unsigned pair_pos_2[num_pair_pos_2];
+
+ unsigned* device_tables = (unsigned*) calloc (num_pair_pos_2 * num_class_1 * num_class_2,
+ sizeof(unsigned));
+
+ // Total glyphs = num_class_1 * num_pair_pos_2
+ for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+ {
+ unsigned start_glyph = 5 + i * num_class_1;
+ if (num_class_2 >= num_class_1)
+ {
+ class_def_2[i] = add_class_def (11,
+ 10 + num_class_2, c);
+ class_def_1[i] = add_class_def (start_glyph + 1,
+ start_glyph + num_class_1,
+ c);
+ } else {
+ class_def_1[i] = add_class_def (start_glyph + 1,
+ start_glyph + num_class_1,
+ c);
+ class_def_2[i] = add_class_def (11,
+ 10 + num_class_2, c);
+ }
+
+ coverage[i] = add_coverage (start_glyph,
+ start_glyph + num_class_1 - 1,
+ c);
+
+ if (with_device_tables)
+ {
+ for(int j = (i + 1) * num_class_1 * num_class_2 - 1;
+ j >= i * num_class_1 * num_class_2;
+ j--)
+ {
+ uint8_t table[] = {
+ (uint8_t) ((j >> 8) & 0xFF),
+ (uint8_t) (j & 0xFF),
+ };
+ device_tables[j] = add_object ((char*) table, 2, c);
+ }
+ }
+
+ pair_pos_2[i] = add_pair_pos_2 (1 + i * num_class_1,
+ coverage[i],
+ class_def_1[i], num_class_1,
+ class_def_2[i], num_class_2,
+ with_device_tables
+ ? &device_tables[i * num_class_1 * num_class_2]
+ : nullptr,
+ c);
+ }
+
+
+ unsigned pair_pos_1 = 0;
+ if (extra_table) pair_pos_1 = add_object (large_string.c_str(), 100000, c);
+
+ if (as_extension) {
+ for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+ pair_pos_2[i] = add_extension (pair_pos_2[i], 2, c);
+
+ if (extra_table)
+ pair_pos_1 = add_extension (pair_pos_1, 2, c);
+ }
+
+ start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_2, c);
+
+ if (extra_table)
+ add_offset (pair_pos_1, c);
+
+ for (int i = 0; i < num_pair_pos_2; i++)
+ add_offset (pair_pos_2[i], c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+
+ free (device_tables);
+}
+
+template<int mark_count,
+ int class_count,
+ int base_count,
+ int table_count>
+static void
+populate_serializer_with_large_mark_base_pos_1 (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ MarkBasePosBuffers<mark_count, class_count, base_count, table_count> buffers (c);
+
+ unsigned mark_base_pos[table_count];
+ for (unsigned i = 0; i < table_count; i++)
+ mark_base_pos[i] = buffers.create_mark_base_pos_1 (i, c);
+
+ for (int i = 0; i < table_count; i++)
+ mark_base_pos[i] = add_extension (mark_base_pos[i], 4, c);
+
+ start_lookup (9, table_count, c);
+
+ for (int i = 0; i < table_count; i++)
+ add_offset (mark_base_pos[i], c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
}
static void test_sort_shortest ()
@@ -852,26 +1476,27 @@ static void test_sort_shortest ()
graph_t graph (c.object_graph ());
graph.sort_shortest_distance ();
+ assert (!graph.in_error ());
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
- assert(graph.object (4).links.length == 3);
- assert(graph.object (4).links[0].objidx == 2);
- assert(graph.object (4).links[1].objidx == 0);
- assert(graph.object (4).links[2].objidx == 3);
+ assert(graph.object (4).real_links.length == 3);
+ assert(graph.object (4).real_links[0].objidx == 2);
+ assert(graph.object (4).real_links[1].objidx == 0);
+ assert(graph.object (4).real_links[2].objidx == 3);
assert(strncmp (graph.object (3).head, "mn", 2) == 0);
- assert(graph.object (3).links.length == 0);
+ assert(graph.object (3).real_links.length == 0);
assert(strncmp (graph.object (2).head, "def", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 1);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 1);
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
- assert(graph.object (1).links.length == 1);
- assert(graph.object (1).links[0].objidx == 0);
+ assert(graph.object (1).real_links.length == 1);
+ assert(graph.object (1).real_links[0].objidx == 0);
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -887,27 +1512,27 @@ static void test_duplicate_leaf ()
graph.duplicate (4, 1);
assert(strncmp (graph.object (5).head, "abc", 3) == 0);
- assert(graph.object (5).links.length == 3);
- assert(graph.object (5).links[0].objidx == 3);
- assert(graph.object (5).links[1].objidx == 4);
- assert(graph.object (5).links[2].objidx == 0);
+ assert(graph.object (5).real_links.length == 3);
+ assert(graph.object (5).real_links[0].objidx == 3);
+ assert(graph.object (5).real_links[1].objidx == 4);
+ assert(graph.object (5).real_links[2].objidx == 0);
assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
- assert(graph.object (4).links.length == 0);
+ assert(graph.object (4).real_links.length == 0);
assert(strncmp (graph.object (3).head, "def", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 2);
+ assert(graph.object (3).real_links.length == 1);
+ assert(graph.object (3).real_links[0].objidx == 2);
assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 1);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 1);
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
- assert(graph.object (1).links.length == 0);
+ assert(graph.object (1).real_links.length == 0);
assert(strncmp (graph.object (0).head, "mn", 2) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -923,32 +1548,32 @@ static void test_duplicate_interior ()
graph.duplicate (3, 2);
assert(strncmp (graph.object (6).head, "abc", 3) == 0);
- assert(graph.object (6).links.length == 3);
- assert(graph.object (6).links[0].objidx == 4);
- assert(graph.object (6).links[1].objidx == 2);
- assert(graph.object (6).links[2].objidx == 1);
+ assert(graph.object (6).real_links.length == 3);
+ assert(graph.object (6).real_links[0].objidx == 4);
+ assert(graph.object (6).real_links[1].objidx == 2);
+ assert(graph.object (6).real_links[2].objidx == 1);
assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
- assert(graph.object (5).links.length == 1);
- assert(graph.object (5).links[0].objidx == 0);
+ assert(graph.object (5).real_links.length == 1);
+ assert(graph.object (5).real_links[0].objidx == 0);
assert(strncmp (graph.object (4).head, "def", 3) == 0);
- assert(graph.object (4).links.length == 1);
- assert(graph.object (4).links[0].objidx == 3);
+ assert(graph.object (4).real_links.length == 1);
+ assert(graph.object (4).real_links[0].objidx == 3);
assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 5);
+ assert(graph.object (3).real_links.length == 1);
+ assert(graph.object (3).real_links[0].objidx == 5);
assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 0);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 0);
assert(strncmp (graph.object (1).head, "mn", 2) == 0);
- assert(graph.object (1).links.length == 0);
+ assert(graph.object (1).real_links.length == 0);
assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -962,19 +1587,14 @@ test_serialize ()
populate_serializer_simple (&c1);
hb_bytes_t expected = c1.copy_bytes ();
- void* buffer_2 = malloc (buffer_size);
- hb_serialize_context_t c2 (buffer_2, buffer_size);
-
graph_t graph (c1.object_graph ());
- graph.serialize (&c2);
- hb_bytes_t actual = c2.copy_bytes ();
+ hb_blob_t* out = graph::serialize (graph);
+ free (buffer_1);
+ hb_bytes_t actual = out->as_bytes ();
assert (actual == expected);
-
- actual.fini ();
expected.fini ();
- free (buffer_1);
- free (buffer_2);
+ hb_blob_destroy (out);
}
static void test_will_overflow_1 ()
@@ -985,7 +1605,7 @@ static void test_will_overflow_1 ()
populate_serializer_complex_2 (&c);
graph_t graph (c.object_graph ());
- assert (!graph.will_overflow (nullptr));
+ assert (!graph::will_overflow (graph, nullptr));
free (buffer);
}
@@ -998,7 +1618,7 @@ static void test_will_overflow_2 ()
populate_serializer_with_overflow (&c);
graph_t graph (c.object_graph ());
- assert (graph.will_overflow (nullptr));
+ assert (graph::will_overflow (graph, nullptr));
free (buffer);
}
@@ -1011,7 +1631,7 @@ static void test_will_overflow_3 ()
populate_serializer_with_dedup_overflow (&c);
graph_t graph (c.object_graph ());
- assert (graph.will_overflow (nullptr));
+ assert (graph::will_overflow (graph, nullptr));
free (buffer);
}
@@ -1024,17 +1644,13 @@ static void test_resolve_overflows_via_sort ()
populate_serializer_with_overflow (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (80000 + 3 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_duplication ()
@@ -1045,17 +1661,13 @@ static void test_resolve_overflows_via_duplication ()
populate_serializer_with_dedup_overflow (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_space_assignment ()
@@ -1085,19 +1697,15 @@ static void test_resolve_overflows_via_isolation ()
populate_serializer_with_isolation_overflow (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
assert (c.offset_overflow ());
- hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (1 + 10000 + 60000 + 1 + 1
+ 4 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_isolation_with_recursive_duplication ()
@@ -1164,21 +1772,207 @@ static void test_resolve_overflows_via_isolation_spaces ()
populate_serializer_with_isolation_overflow_spaces (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
assert (c.offset_overflow ());
- hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
unsigned expected_length = 3 + 2 * 60000; // objects
expected_length += 2 * 4 + 2 * 2; // links
assert (result.length == expected_length);
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
+}
+
+static void test_resolve_mixed_overflows_via_isolation_spaces ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_24_and_32_bit_offsets (&c);
+ graph_t graph (c.object_graph ());
+
+ assert (c.offset_overflow ());
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
+
+ unsigned expected_length =
+ // Objects
+ 7 +
+ 4 * 40000;
+
+ expected_length +=
+ // Links
+ 2 * 4 + // 32
+ 4 * 3 + // 24
+ 4 * 2; // 16
+
+ assert (result.length == expected_length);
+
+ free (buffer);
+ hb_blob_destroy (out);
+}
+
+static void test_resolve_with_extension_promotion ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_extension_promotion (&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_extension_promotion (&e, 3);
+
+ run_resolve_overflow_test ("test_resolve_with_extension_promotion",
+ c,
+ e,
+ 20,
+ true);
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <1, 4>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_extension_pair_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <1, 4>(&c, true);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_extension_pair_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_2_split ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 4, 3000>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 2, 3000>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_2_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_close_to_limit_pair_pos_2_split ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 1596, 10>(&c, true, false, false);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 798, 10>(&e, true, false, false);
+
+ run_resolve_overflow_test ("test_resolve_with_close_to_limit_pair_pos_2_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_pair_pos_2_split_with_device_tables ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 4, 2000>(&c, false, true);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 2, 2000>(&e, true, true);
+
+ run_resolve_overflow_test ("test_resolve_with_pair_pos_2_split_with_device_tables",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_mark_base_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 1>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 2>(&e);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_mark_base_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
}
static void test_resolve_overflows_via_splitting_spaces ()
@@ -1221,6 +2015,26 @@ static void test_resolve_overflows_via_splitting_spaces_2 ()
free (expected_buffer);
}
+static void test_resolve_overflows_via_priority ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_priority_overflow (&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_priority_overflow_expected (&e);
+
+ run_resolve_overflow_test ("test_resolve_overflows_via_priority",
+ c,
+ e,
+ 3);
+ free (buffer);
+ free (expected_buffer);
+}
+
+
static void test_virtual_link ()
{
size_t buffer_size = 100;
@@ -1228,13 +2042,10 @@ static void test_virtual_link ()
hb_serialize_context_t c (buffer, buffer_size);
populate_serializer_virtual_link (&c);
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
-
- hb_bytes_t result = out.copy_bytes ();
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == 5 + 4 * 2);
assert (result[0] == 'a');
assert (result[5] == 'c');
@@ -1242,11 +2053,47 @@ static void test_virtual_link ()
assert (result[9] == 'b');
assert (result[12] == 'd');
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
+static void
+test_shared_node_with_virtual_links ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+
+ c.start_serialize<char> ();
+
+ unsigned obj_b = add_object ("b", 1, &c);
+ unsigned obj_c = add_object ("c", 1, &c);
+
+ start_object ("d", 1, &c);
+ add_virtual_offset (obj_b, &c);
+ unsigned obj_d_1 = c.pop_pack ();
+
+ start_object ("d", 1, &c);
+ add_virtual_offset (obj_c, &c);
+ unsigned obj_d_2 = c.pop_pack ();
+
+ assert (obj_d_1 == obj_d_2);
+
+ start_object ("a", 1, &c);
+ add_offset (obj_b, &c);
+ add_offset (obj_c, &c);
+ add_offset (obj_d_1, &c);
+ add_offset (obj_d_2, &c);
+ c.pop_pack ();
+ c.end_serialize ();
+
+ assert(c.object_graph() [obj_d_1]->virtual_links.length == 2);
+ assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b);
+ assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c);
+ free(buffer);
+}
+
+
// TODO(garretrieger): update will_overflow tests to check the overflows array.
// TODO(garretrieger): add tests for priority raising.
@@ -1254,14 +2101,13 @@ int
main (int argc, char **argv)
{
test_serialize ();
- test_sort_kahn_1 ();
- test_sort_kahn_2 ();
test_sort_shortest ();
test_will_overflow_1 ();
test_will_overflow_2 ();
test_will_overflow_3 ();
test_resolve_overflows_via_sort ();
test_resolve_overflows_via_duplication ();
+ test_resolve_overflows_via_priority ();
test_resolve_overflows_via_space_assignment ();
test_resolve_overflows_via_isolation ();
test_resolve_overflows_via_isolation_with_recursive_duplication ();
@@ -1270,7 +2116,23 @@ main (int argc, char **argv)
test_resolve_overflows_via_isolating_16bit_space_2 ();
test_resolve_overflows_via_splitting_spaces ();
test_resolve_overflows_via_splitting_spaces_2 ();
+ test_resolve_mixed_overflows_via_isolation_spaces ();
test_duplicate_leaf ();
test_duplicate_interior ();
test_virtual_link ();
+ test_shared_node_with_virtual_links ();
+ test_resolve_with_extension_promotion ();
+ test_resolve_with_basic_pair_pos_1_split ();
+ test_resolve_with_extension_pair_pos_1_split ();
+ test_resolve_with_basic_pair_pos_2_split ();
+ test_resolve_with_pair_pos_2_split_with_device_tables ();
+ test_resolve_with_close_to_limit_pair_pos_2_split ();
+ test_resolve_with_basic_mark_base_pos_1_split ();
+
+ // TODO(grieger): have run overflow tests compare graph equality not final packed binary.
+ // TODO(grieger): split test where multiple subtables in one lookup are split to test link ordering.
+ // TODO(grieger): split test where coverage table in subtable that is being split is shared.
+ // TODO(grieger): test with extensions already mixed in as well.
+ // TODO(grieger): test two layer ext promotion setup.
+ // TODO(grieger): test sorting by subtables per byte in ext. promotion.
}
diff --git a/src/test-serialize.cc b/src/test-serialize.cc
new file mode 100644
index 000000000..4c90abb11
--- /dev/null
+++ b/src/test-serialize.cc
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ */
+
+#include "hb.hh"
+#include "hb-serialize.hh"
+#include "hb-ot-layout-common.hh"
+
+using OT::Layout::Common::Coverage;
+
+int
+main (int argc, char **argv)
+{
+ char buf[16384];
+
+ hb_serialize_context_t s (buf, sizeof (buf));
+
+ hb_sorted_vector_t<hb_codepoint_t> v{1, 2, 5};
+
+ auto c = s.start_serialize<Coverage> ();
+
+ c->serialize (&s, hb_iter (v));
+
+ s.end_serialize ();
+
+ hb_bytes_t bytes = s.copy_bytes ();
+ assert (bytes.length == 10);
+ bytes.fini ();
+
+ return 0;
+}
diff --git a/src/test-set.cc b/src/test-set.cc
index 286f1a997..e760c98f8 100644
--- a/src/test-set.cc
+++ b/src/test-set.cc
@@ -20,13 +20,11 @@
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
*/
#include "hb.hh"
#include "hb-set.hh"
-
int
main (int argc, char **argv)
{
@@ -36,27 +34,34 @@ main (int argc, char **argv)
hb_set_t v1 {1, 2};
hb_set_t v2 {v1};
assert (v1.get_population () == 2);
+ assert (hb_len (hb_iter (v1)) == 2);
assert (v2.get_population () == 2);
}
/* Test copy assignment. */
{
hb_set_t v1 {1, 2};
- hb_set_t v2 = v1;
+ hb_set_t v2;
+ v2 = v1;
assert (v1.get_population () == 2);
assert (v2.get_population () == 2);
}
/* Test move constructor. */
{
- hb_set_t v {hb_set_t {1, 2}};
+ hb_set_t s {1, 2};
+ hb_set_t v (std::move (s));
+ assert (s.get_population () == 0);
+ assert (hb_len (hb_iter (s)) == 0);
assert (v.get_population () == 2);
}
/* Test move assignment. */
{
+ hb_set_t s = hb_set_t {1, 2};
hb_set_t v;
- v = hb_set_t {1, 2};
+ v = std::move (s);
+ assert (s.get_population () == 0);
assert (v.get_population () == 2);
}
@@ -67,9 +72,15 @@ main (int argc, char **argv)
s.add (18);
s.add (12);
- hb_set_t v (s);
+ hb_vector_t<hb_codepoint_t> v (s);
+ hb_set_t v0 (v);
+ hb_set_t v1 (s);
+ hb_set_t v2 (std::move (s));
- assert (v.get_population () == 2);
+ assert (s.get_population () == 0);
+ assert (v0.get_population () == 2);
+ assert (v1.get_population () == 2);
+ assert (v2.get_population () == 2);
}
/* Test initializing from iterator. */
@@ -77,11 +88,14 @@ main (int argc, char **argv)
hb_set_t s;
s.add (18);
- s.add (12);
+ s << 12;
+
+ /* Sink a range. */
+ s << hb_pair_t<hb_codepoint_t, hb_codepoint_t> {1, 3};
hb_set_t v (hb_iter (s));
- assert (v.get_population () == 2);
+ assert (v.get_population () == 5);
}
/* Test initializing from initializer list and swapping. */
diff --git a/src/test-use-table.cc b/src/test-use-table.cc
new file mode 100644
index 000000000..70d2d41f4
--- /dev/null
+++ b/src/test-use-table.cc
@@ -0,0 +1,18 @@
+#include "hb-ot-shaper-use-table.hh"
+
+int main (int argc, char **argv)
+{
+ if (argc != 2)
+ {
+ for (unsigned u = 0; u < 0x10FFFFu; u++)
+ printf ("U+%04X %d\n", u, hb_use_get_category (u));
+ return 0;
+ }
+
+ hb_codepoint_t u;
+ sscanf (argv[1], "%x", &u);
+
+ printf ("%d\n", hb_use_get_category (u));
+
+ return 0;
+}
diff --git a/src/test-vector.cc b/src/test-vector.cc
index 6418a84ae..65e51c657 100644
--- a/src/test-vector.cc
+++ b/src/test-vector.cc
@@ -26,11 +26,14 @@
#include "hb.hh"
#include "hb-vector.hh"
#include "hb-set.hh"
+#include "hb-map.hh"
+#include <string>
int
main (int argc, char **argv)
{
+ assert (sizeof (hb_vector_t<int>) == sizeof (hb_sorted_vector_t<int>));
/* Test copy constructor. */
{
@@ -60,8 +63,12 @@ main (int argc, char **argv)
/* Test move constructor. */
{
- hb_vector_t<int> v {hb_vector_t<int> {1, 2}};
- hb_vector_t<int> V {hb_vector_t<int> {1, 2}};
+ hb_vector_t<int> s {1, 2};
+ hb_sorted_vector_t<int> S {1, 2};
+ hb_vector_t<int> v (std::move (s));
+ hb_sorted_vector_t<int> V (std::move (S));
+ assert (s.length == 0);
+ assert (S.length == 0);
assert (v.length == 2);
assert (v[0] == 1);
assert (v[1] == 2);
@@ -69,11 +76,16 @@ main (int argc, char **argv)
/* Test move assignment. */
{
+ hb_vector_t<int> s {1, 2};
+ hb_sorted_vector_t<int> S {1, 2};
hb_vector_t<int> v;
hb_sorted_vector_t<int> V;
- v = hb_vector_t<int> {1, 2};
- V = hb_sorted_vector_t<int> {1, 2};
+ v = std::move (s);
+ V = std::move (S);
+ assert (s.length == 0);
+ assert (S.length == 0);
assert (v.length == 2);
+ assert (V.length == 2);
assert (v[0] == 1);
assert (v[1] == 2);
}
@@ -136,5 +148,39 @@ main (int argc, char **argv)
assert (v2[2] == 3);
}
+ {
+ hb_vector_t<std::string> v;
+
+ std::string s;
+ for (unsigned i = 1; i < 100; i++)
+ {
+ s += "x";
+ v.push (s);
+ }
+
+ hb_vector_t<std::string> v2;
+
+ v2 = v;
+
+ v2.remove_ordered (50);
+ v2.remove_unordered (50);
+ }
+
+ {
+ hb_vector_t<hb_set_t> v;
+ hb_set_t s {1, 5, 7};
+ v.push (s);
+ v << s;
+ assert (s.get_population () == 3);
+ v << std::move (s);
+ assert (s.get_population () == 0);
+ }
+
+ {
+ hb_vector_t<hb_map_t> v;
+ hb_map_t m;
+ v.push (m);
+ }
+
return 0;
}
diff --git a/src/update-unicode-tables.make b/src/update-unicode-tables.make
index 8c2eaa418..6f5b490f7 100755
--- a/src/update-unicode-tables.make
+++ b/src/update-unicode-tables.make
@@ -1,42 +1,42 @@
#!/usr/bin/env -S make -f
all: packtab \
- hb-ot-shape-complex-arabic-joining-list.hh \
- hb-ot-shape-complex-arabic-table.hh hb-unicode-emoji-table.hh \
- hb-ot-shape-complex-indic-table.cc hb-ot-tag-table.hh \
- hb-ucd-table.hh hb-ot-shape-complex-use-table.hh \
- hb-ot-shape-complex-vowel-constraints.cc
+ hb-ot-shaper-arabic-joining-list.hh \
+ hb-ot-shaper-arabic-table.hh hb-unicode-emoji-table.hh \
+ hb-ot-shaper-indic-table.cc hb-ot-tag-table.hh \
+ hb-ucd-table.hh hb-ot-shaper-use-table.hh \
+ hb-ot-shaper-vowel-constraints.cc
.PHONY: all clean packtab
-hb-ot-shape-complex-arabic-joining-list.hh: gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt
+hb-ot-shaper-arabic-joining-list.hh: gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt
./$^ > $@ || ($(RM) $@; false)
-hb-ot-shape-complex-arabic-table.hh: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
+hb-ot-shaper-arabic-table.hh: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
./$^ > $@ || ($(RM) $@; false)
hb-unicode-emoji-table.hh: gen-emoji-table.py emoji-data.txt emoji-test.txt
./$^ > $@ || ($(RM) $@; false)
-hb-ot-shape-complex-indic-table.cc: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+hb-ot-shaper-indic-table.cc: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
./$^ > $@ || ($(RM) $@; false)
hb-ot-tag-table.hh: gen-tag-table.py languagetags language-subtag-registry
./$^ > $@ || ($(RM) $@; false)
hb-ucd-table.hh: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
./$^ > $@ || ($(RM) $@; false)
-hb-ot-shape-complex-use-table.hh: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt ms-use/IndicSyllabicCategory-Additional.txt ms-use/IndicPositionalCategory-Additional.txt
+hb-ot-shaper-use-table.hh: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt ms-use/IndicSyllabicCategory-Additional.txt ms-use/IndicPositionalCategory-Additional.txt
./$^ > $@ || ($(RM) $@; false)
-hb-ot-shape-complex-vowel-constraints.cc: gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
+hb-ot-shaper-vowel-constraints.cc: gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
./$^ > $@ || ($(RM) $@; false)
packtab:
/usr/bin/env python3 -c "import packTab" 2>/dev/null || /usr/bin/env python3 -m pip install git+https://github.com/harfbuzz/packtab
-ArabicShaping.txt DerivedCoreProperties.txt IndicPositionalCategory.txt IndicSyllabicCategory.txt Scripts.txt UnicodeData.txt:
+ArabicShaping.txt Blocks.txt DerivedCoreProperties.txt IndicPositionalCategory.txt IndicSyllabicCategory.txt Scripts.txt UnicodeData.txt:
curl -O https://unicode.org/Public/UCD/latest/ucd/$@
emoji-data.txt:
curl -O https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
emoji-test.txt:
curl -O https://www.unicode.org/Public/emoji/latest/emoji-test.txt
languagetags:
- curl -O https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
+ curl -O https://learn.microsoft.com/en-us/typography/opentype/spec/languagetags
language-subtag-registry:
curl -O https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
ucd.nounihan.grouped.zip:
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index ea3bb20dc..9cdd68801 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -1,6 +1,6 @@
/freetype2
/glib
/packagecache
-/benchmark-1.4.1
+/benchmark-*
/cairo
/ragel-6.10
diff --git a/subprojects/cairo.wrap b/subprojects/cairo.wrap
index afb2695d4..afb7e7425 100644
--- a/subprojects/cairo.wrap
+++ b/subprojects/cairo.wrap
@@ -2,4 +2,7 @@
directory=cairo
url=https://gitlab.freedesktop.org/cairo/cairo.git
depth=1
-revision=1.17.4
+revision=c90faeb7492b1b778d18a796afe5c2e4b32a6356
+
+[provide]
+dependency_names = cairo, cairo-ft
diff --git a/subprojects/freetype2.wrap b/subprojects/freetype2.wrap
index c346deb01..1ff89ecd1 100644
--- a/subprojects/freetype2.wrap
+++ b/subprojects/freetype2.wrap
@@ -1,4 +1,10 @@
-[wrap-git]
-directory=freetype
-url=https://gitlab.freedesktop.org/freetype/freetype.git
-revision=VER-2-11-0
+[wrap-file]
+directory = freetype-2.12.1
+source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.xz
+source_filename = freetype-2.12.1.tar.xz
+source_hash = 4766f20157cc4cf0cd292f80bf917f92d1c439b243ac3018debf6b9140c41a7f
+wrapdb_version = 2.12.1-2
+
+[provide]
+freetype2 = freetype_dep
+freetype = freetype_dep
diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap
index 7a4eae175..a865af423 100644
--- a/subprojects/glib.wrap
+++ b/subprojects/glib.wrap
@@ -1,6 +1,11 @@
-[wrap-git]
-directory=glib
-url=https://gitlab.gnome.org/GNOME/glib.git
-depth=1
-push-url=git@gitlab.gnome.org:GNOME/glib.git
-revision=2.58.1
+[wrap-file]
+directory = glib-2.74.1
+source_url = https://download.gnome.org/sources/glib/2.74/glib-2.74.1.tar.xz
+source_fallback_url = https://ftp.acc.umu.se/pub/gnome/sources/glib/2.74/glib-2.74.1.tar.xz
+source_filename = glib-2.74.1.tar.xz
+source_hash = 0ab981618d1db47845e56417b0d7c123f81a3427b2b9c93f5a46ff5bbb964964
+wrapdb_version = 2.74.1-1
+
+[provide]
+dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0
+program_names = glib-genmarshal, glib-mkenums, glib-compile-schemas, glib-compile-resources, gio-querymodules, gdbus-codegen
diff --git a/subprojects/google-benchmark.wrap b/subprojects/google-benchmark.wrap
index 876927d6e..6205cd7f7 100644
--- a/subprojects/google-benchmark.wrap
+++ b/subprojects/google-benchmark.wrap
@@ -1,9 +1,12 @@
[wrap-file]
-directory = benchmark-1.5.2
-source_url = https://github.com/google/benchmark/archive/v1.5.2.zip
-source_filename = benchmark-1.5.2.zip
-source_hash = 21e6e096c9a9a88076b46bd38c33660f565fa050ca427125f64c4a8bf60f336b
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/google-benchmark/1.5.2/1/get_zip
-patch_filename = google-benchmark-1.5.2-1-wrap.zip
-patch_hash = 49f41e4a7e68ac258b6509b9de9857441903be4fb473454c4cba8be885f0c6c3
+directory = benchmark-1.7.1
+source_url = https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+source_filename = benchmark-1.7.1.tar.gz
+source_hash = 6430e4092653380d9dc4ccb45a1e2dc9259d581f4866dc0759713126056bc1d7
+patch_filename = google-benchmark_1.7.1-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/google-benchmark_1.7.1-1/get_patch
+patch_hash = 9c6694328ac971cd781aa67c45c64291c087f118e23b75946f52670caacf49b7
+wrapdb_version = 1.7.1-1
+[provide]
+benchmark = google_benchmark_dep
diff --git a/subprojects/ttf-parser.wrap b/subprojects/ttf-parser.wrap
deleted file mode 100644
index 11cda5457..000000000
--- a/subprojects/ttf-parser.wrap
+++ /dev/null
@@ -1,5 +0,0 @@
-[wrap-git]
-directory=ttf-parser
-url=https://github.com/RazrFalcon/ttf-parser.git
-depth=1
-revision=master
diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap
new file mode 100644
index 000000000..23af071a2
--- /dev/null
+++ b/subprojects/zlib.wrap
@@ -0,0 +1,12 @@
+[wrap-file]
+directory = zlib-1.2.13
+source_url = http://zlib.net/fossils/zlib-1.2.13.tar.gz
+source_filename = zlib-1.2.13.tar.gz
+source_hash = b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30
+patch_filename = zlib_1.2.13-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.2.13-2/get_patch
+patch_hash = a7abea3ad65dc2c291ad5fbbf5355d0585a7f7b8c935d4a74335b8fe18684506
+wrapdb_version = 1.2.13-2
+
+[provide]
+zlib = zlib_dep
diff --git a/test/Makefile.am b/test/Makefile.am
index 01d542a00..10f90958f 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,7 +2,7 @@
NULL =
EXTRA_DIST =
-SUBDIRS = api shape subset fuzzing
+SUBDIRS = api shape subset fuzzing threads
EXTRA_DIST += \
meson.build \
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 883464cea..ffd4a0fc6 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -30,6 +30,8 @@ noinst_PROGRAMS = $(TEST_PROGS)
TEST_PROGS = \
test-aat-layout \
test-baseline \
+ test-be-glyph-advance \
+ test-be-num-glyphs \
test-blob \
test-buffer \
test-c \
@@ -76,11 +78,15 @@ TEST_PROGS = \
test-subset-gpos \
test-subset-colr \
test-subset-cbdt \
+ test-subset-repacker \
test-unicode \
test-var-coords \
test-version \
$(NULL)
+test_draw_CPPFLAGS = $(AM_CPPFLAGS)
+test_draw_LDADD = $(LDADD)
+
test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@@ -100,6 +106,7 @@ test_subset_cbdt_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_colr_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_repacker_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_unicode_CPPFLAGS = \
$(AM_CPPFLAGS) \
@@ -123,6 +130,9 @@ endif
endif
if HAVE_FREETYPE
+test_draw_CPPFLAGS += $(FREETYPE_CFLAGS)
+test_draw_LDADD += $(FREETYPE_LIBS)
+
TEST_PROGS += \
test-ot-math \
$(NULL)
diff --git a/test/api/fonts/base2.ttf b/test/api/fonts/base2.ttf
new file mode 100644
index 000000000..5cb0d35ba
--- /dev/null
+++ b/test/api/fonts/base2.ttf
Binary files differ
diff --git a/test/api/fonts/nameID.override.expected.ttf b/test/api/fonts/nameID.override.expected.ttf
new file mode 100644
index 000000000..d17ea83cd
--- /dev/null
+++ b/test/api/fonts/nameID.override.expected.ttf
Binary files differ
diff --git a/test/api/fonts/notosansitalic.ttf b/test/api/fonts/notosansitalic.ttf
new file mode 100644
index 000000000..26a80c557
--- /dev/null
+++ b/test/api/fonts/notosansitalic.ttf
Binary files differ
diff --git a/test/api/fonts/repacker_expected.otf b/test/api/fonts/repacker_expected.otf
new file mode 100644
index 000000000..f96fde0ca
--- /dev/null
+++ b/test/api/fonts/repacker_expected.otf
Binary files differ
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 7390e57a7..2be47beb7 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -27,9 +27,7 @@
#ifndef HB_TEST_H
#define HB_TEST_H
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <hb-config.hh>
#include <hb-glib.h>
@@ -52,6 +50,17 @@ HB_BEGIN_DECLS
((const char *) s)[2], \
((const char *) s)[3]))
+#define HB_FACE_ADD_TABLE(face, tag, data) \
+ do { \
+ hb_blob_t *blob = hb_blob_create_or_fail ((data), \
+ sizeof (data), \
+ HB_MEMORY_MODE_READONLY, \
+ NULL, NULL); \
+ hb_face_builder_add_table ((face), \
+ HB_TAG_CHAR4(tag), \
+ blob); \
+ hb_blob_destroy (blob); \
+ } while (0)
static inline const char *
srcdir (void)
diff --git a/test/api/meson.build b/test/api/meson.build
index 7ea295420..f5cdce805 100644
--- a/test/api/meson.build
+++ b/test/api/meson.build
@@ -6,6 +6,8 @@ endif
tests = [
'test-aat-layout.c',
'test-baseline.c',
+ 'test-be-glyph-advance.c',
+ 'test-be-num-glyphs.c',
'test-blob.c',
'test-buffer.c',
'test-c.c',
@@ -30,6 +32,7 @@ tests = [
'test-ot-tag.c',
'test-ot-extents-cff.c',
'test-ot-metrics-tt-var.c',
+ 'test-subset-repacker.c',
'test-set.c',
'test-shape.c',
'test-style.c',
diff --git a/test/api/test-baseline.c b/test/api/test-baseline.c
index 982c68311..9f9542ea4 100644
--- a/test/api/test-baseline.c
+++ b/test/api/test-baseline.c
@@ -41,6 +41,58 @@ test_ot_layout_base (void)
&position));
g_assert_cmpint (46, ==, position);
+ g_assert (!hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, HB_DIRECTION_TTB,
+ HB_TAG ('h','a','n','i'),
+ HB_TAG ('E','N','G',' '),
+ &position));
+
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_base_with_fallback (void)
+{
+ hb_face_t *face = hb_test_open_font_file ("fonts/base.ttf");
+ hb_font_t *font = hb_font_create (face);
+
+ hb_position_t position;
+ hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, HB_DIRECTION_TTB,
+ HB_TAG ('h','a','n','i'),
+ HB_TAG ('E','N','G',' '),
+ &position);
+ g_assert_cmpint (46, ==, position);
+
+ hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, HB_DIRECTION_TTB,
+ HB_TAG ('h','a','n','i'),
+ HB_TAG ('E','N','G',' '),
+ &position);
+ g_assert_cmpint (1000, ==, position);
+
+ hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_MATH, HB_DIRECTION_LTR,
+ HB_TAG ('h','a','n','i'),
+ HB_TAG ('E','N','G',' '),
+ &position);
+ g_assert_cmpint (271, ==, position);
+
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+
+ face = hb_test_open_font_file ("fonts/base2.ttf");
+ font = hb_font_create (face);
+
+ hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_LTR,
+ HB_SCRIPT_BENGALI,
+ HB_TAG ('E','N','G',' '),
+ &position);
+ g_assert_cmpint (622, ==, position);
+
+ hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_LTR,
+ HB_SCRIPT_TIBETAN,
+ HB_TAG ('E','N','G',' '),
+ &position);
+ g_assert_cmpint (600, ==, position);
+
hb_font_destroy (font);
hb_face_destroy (face);
}
@@ -51,6 +103,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv);
hb_test_add (test_ot_layout_base);
+ hb_test_add (test_ot_layout_base_with_fallback);
return hb_test_run();
}
diff --git a/test/api/test-be-glyph-advance.c b/test/api/test-be-glyph-advance.c
new file mode 100644
index 000000000..300746dcb
--- /dev/null
+++ b/test/api/test-be-glyph-advance.c
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_hmtx (void)
+{
+ hb_face_t *face;
+ hb_font_t *font;
+
+ const char maxp_data[] = "\x00\x00\x50\x00" // version
+ "\x00\x05" // numGlyphs
+ ;
+ const char loca_data[18] = "";
+ const char hhea_data[36] =
+ "\x00\x01\x00\x00" /* FixedVersion<>version; * 0x00010000u for version 1.0. */
+ "\x02\x00" /* FWORD ascender; * Typographic ascent. */
+ "\x00\x10" /* FWORD descender; * Typographic descent. */
+ "\x00\x00" /* FWORD lineGap; * Typographic line gap. */
+ "\x00\x00" /* UFWORD advanceMax; * Maximum advance width/height value in metrics table. */
+ "\x00\x00" /* FWORD minLeadingBearing; * Minimum left/top sidebearing value in metrics table. */
+ "\x00\x00" /* FWORD minTrailingBearing; * Minimum right/bottom sidebearing value; */
+ "\x01\x00" /* FWORD maxExtent; * horizontal: Max(lsb + (xMax - xMin)), */
+ "\x00\x00" /* HBINT16 caretSlopeRise; * Used to calculate the slope of the,*/
+ "\x00\x00" /* HBINT16 caretSlopeRun; * 0 for vertical caret, 1 for horizontal. */
+ "\x00\x00" /* HBINT16 caretOffset; * The amount by which a slanted */
+ "\x00\x00" /* HBINT16 reserved1; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved2; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved3; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved4; * Set to 0. */
+ "\x00\x00" /* HBINT16 metricDataFormat; * 0 for current format. */
+ "\x00\x02" /* HBUINT16 numberOfLongMetrics; * Number of LongMetric entries in metric table. */
+ ;
+ const char hmtx_data[18] =
+ "\x00\x01\x00\x02" /* glyph 0 advance lsb */
+ "\x00\x03\x00\x04" /* glyph 1 advance lsb */
+ "\x00\x05" /* glyph 2 lsb */
+ "\x00\x06" /* glyph 3 lsb */
+ "\x00\x07" /* glyph 4 lsb */
+ "\x00\x08" /* glyph 5 advance */
+ "\x00\x09" /* glyph 6 advance */
+ ;
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ HB_FACE_ADD_TABLE (face, "hhea", hhea_data);
+ HB_FACE_ADD_TABLE (face, "hmtx", hmtx_data);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 0), ==, 1);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 1), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 2), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 3), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 4), ==, 3);
+#ifndef HB_NO_BEYOND_64K
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 5), ==, 8);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 6), ==, 9);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 7), ==, 9);
+#endif
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 8), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 9), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font,10), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font,11), ==, 0);
+ hb_font_destroy (font);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_maxp_and_hmtx);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-be-num-glyphs.c b/test/api/test-be-num-glyphs.c
new file mode 100644
index 000000000..866343fe5
--- /dev/null
+++ b/test/api/test-be-num-glyphs.c
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_loca (void)
+{
+ hb_face_t *face;
+
+ const char maxp_data[] = "\x00\x00\x50\x00" // version
+ "\x00\x05" // numGlyphs
+ ;
+#ifndef HB_NO_BEYOND_64K
+ const char loca_data[18] = "";
+#endif
+
+ face = hb_face_builder_create ();
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 0);
+ hb_face_destroy (face);
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 5);
+ hb_face_destroy (face);
+
+#ifndef HB_NO_BEYOND_64K
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+ hb_face_destroy (face);
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+ hb_face_destroy (face);
+#endif
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_maxp_and_loca);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-c.c b/test/api/test-c.c
index b4518adbc..59eef4242 100644
--- a/test/api/test-c.c
+++ b/test/api/test-c.c
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-/* This file tests that all headers can be included from .c files */
+/* This file tests that all headers can be included from C files */
#ifdef HAVE_CONFIG_H
diff --git a/test/api/test-cplusplus.cc b/test/api/test-cplusplus.cc
index 3313d7460..01b000271 100644
--- a/test/api/test-cplusplus.cc
+++ b/test/api/test-cplusplus.cc
@@ -1,5 +1,6 @@
/*
* Copyright © 2011 Google, Inc.
+ * Copyright © 2022 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -24,7 +25,101 @@
* Google Author(s): Behdad Esfahbod
*/
-/* This file tests that all headers can be included from .cc files */
+/* This file tests that all headers can be included from C++ files,
+ * as well as test the C++ API. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
-#include "test-c.c"
+#include <hb.h>
+#include <hb-subset.h>
+#include <hb-ot.h>
+#include <hb-aat.h>
+
+#ifdef HAVE_GLIB
+#include <hb-glib.h>
+#endif
+
+#ifdef HAVE_ICU
+#include <hb-icu.h>
+#endif
+
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
+
+#ifdef HAVE_UNISCRIBE
+#include <hb-uniscribe.h>
+#endif
+
+#ifdef HAVE_CORETEXT
+#include <hb-coretext.h>
+#endif
+
+
+/* Test C++ API. */
+
+#include "hb-cplusplus.hh"
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+int
+main ()
+{
+ hb_buffer_t *b = hb_buffer_create ();
+ hb::shared_ptr<hb_buffer_t> pb {b};
+
+ /* Test copy-construction. */
+ assert (bool (pb));
+ hb::shared_ptr<hb_buffer_t> pb2 {pb};
+ assert (bool (pb2));
+ assert (bool (pb));
+
+ /* Test move-construction. */
+ assert (bool (pb2));
+ hb::shared_ptr<hb_buffer_t> pb4 {std::move (pb2)};
+ assert (!bool (pb2));
+ assert (bool (pb4));
+
+ /* Test copy-assignment. */
+ hb::shared_ptr<hb_buffer_t> pb3;
+ assert (!bool (pb3));
+ pb3 = pb;
+ assert (bool (pb3));
+ assert (bool (pb));
+
+ /* Test move-assignment. */
+ assert (bool (pb));
+ pb2 = std::move (pb);
+ assert (!bool (pb));
+
+ pb.reference ();
+ pb.destroy ();
+
+ pb3.reference ();
+ pb3.destroy ();
+
+ pb3.swap (pb4);
+
+ hb_user_data_key_t key;
+ pb.set_user_data (&key, b, nullptr, true);
+ (void) pb.get_user_data (&key);
+
+ hb::unique_ptr<hb_buffer_t> pb5 {pb3.reference ()};
+
+
+ /* Test that shared_ptr / unique_ptr are std::hash'able, and that they
+ * return the same hash (which is the underlying pointer's hash. */
+ std::hash<hb_buffer_t *> hash {};
+ std::hash<hb::shared_ptr<hb_buffer_t>> hash2 {};
+ std::hash<hb::unique_ptr<hb_buffer_t>> hash3 {};
+
+ assert (hash (b) == hash2 (pb4));
+ assert (hash2 (pb4) == hash2 (pb2));
+ assert (hash (b) == hash3 (pb5));
+
+ return pb == pb.get_empty () || pb == pb2;
+}
diff --git a/test/api/test-draw.c b/test/api/test-draw.c
index c502f7d3a..32c8e5618 100644
--- a/test/api/test-draw.c
+++ b/test/api/test-draw.c
@@ -23,16 +23,19 @@
*/
#include "hb-test.h"
+#include <math.h>
#include <hb.h>
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
-#ifdef HB_EXPERIMENTAL_API
-typedef struct user_data_t
+typedef struct draw_data_t
{
char *str;
unsigned size;
unsigned consumed;
-} user_data_t;
+} draw_data_t;
/* Our modified itoa, why not using libc's? it is going to be used
in harfbuzzjs where libc isn't available */
@@ -47,8 +50,9 @@ static void _hb_reverse (char *buf, unsigned int len)
start++; end--;
}
}
-static unsigned _hb_itoa (int32_t num, char *buf)
+static unsigned _hb_itoa (float fnum, char *buf)
{
+ int32_t num = (int32_t) floorf (fnum + .5f);
unsigned int i = 0;
hb_bool_t is_negative = num < 0;
if (is_negative) num = -num;
@@ -95,69 +99,81 @@ test_itoa (void)
}
static void
-move_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
+move_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data)
{
/* 4 = command character space + comma + array starts with 0 index + nul character space */
- if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return;
- user_data->str[user_data->consumed++] = 'M';
- user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+ if (draw_data->consumed + 2 * ITOA_BUF_SIZE + 4 > draw_data->size) return;
+ draw_data->str[draw_data->consumed++] = 'M';
+ draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
}
static void
-line_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
+line_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data)
{
- if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return;
- user_data->str[user_data->consumed++] = 'L';
- user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+ if (draw_data->consumed + 2 * ITOA_BUF_SIZE + 4 > draw_data->size) return;
+ draw_data->str[draw_data->consumed++] = 'L';
+ draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
}
static void
-quadratic_to (hb_position_t control_x, hb_position_t control_y,
- hb_position_t to_x, hb_position_t to_y,
- user_data_t *user_data)
+quadratic_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *user_data)
{
- if (user_data->consumed + 4 * ITOA_BUF_SIZE + 6 > user_data->size) return;
- user_data->str[user_data->consumed++] = 'Q';
- user_data->consumed += _hb_itoa (control_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (control_y, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ' ';
- user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+ if (draw_data->consumed + 4 * ITOA_BUF_SIZE + 6 > draw_data->size) return;
+ draw_data->str[draw_data->consumed++] = 'Q';
+ draw_data->consumed += _hb_itoa (control_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (control_y, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ' ';
+ draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
}
static void
-cubic_to (hb_position_t control1_x, hb_position_t control1_y,
- hb_position_t control2_x, hb_position_t control2_y,
- hb_position_t to_x, hb_position_t to_y,
- user_data_t *user_data)
+cubic_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *user_data)
{
- if (user_data->consumed + 6 * ITOA_BUF_SIZE + 8 > user_data->size) return;
- user_data->str[user_data->consumed++] = 'C';
- user_data->consumed += _hb_itoa (control1_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (control1_y, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ' ';
- user_data->consumed += _hb_itoa (control2_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (control2_y, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ' ';
- user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
- user_data->str[user_data->consumed++] = ',';
- user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+ if (draw_data->consumed + 6 * ITOA_BUF_SIZE + 8 > draw_data->size) return;
+ draw_data->str[draw_data->consumed++] = 'C';
+ draw_data->consumed += _hb_itoa (control1_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (control1_y, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ' ';
+ draw_data->consumed += _hb_itoa (control2_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (control2_y, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ' ';
+ draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+ draw_data->str[draw_data->consumed++] = ',';
+ draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
}
static void
-close_path (user_data_t *user_data)
+close_path (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+ hb_draw_state_t *st,
+ void *user_data)
{
- if (user_data->consumed + 2 > user_data->size) return;
- user_data->str[user_data->consumed++] = 'Z';
+ if (draw_data->consumed + 2 > draw_data->size) return;
+ draw_data->str[draw_data->consumed++] = 'Z';
}
static hb_draw_funcs_t *funcs;
@@ -166,7 +182,7 @@ static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic
static void
test_hb_draw_empty (void)
{
- g_assert (!hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL));
+ hb_font_get_glyph_shape (hb_font_get_empty (), 3, funcs, NULL);
}
static void
@@ -177,17 +193,17 @@ test_hb_draw_glyf (void)
hb_face_destroy (face);
char str[1024];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str),
.consumed = 0
};
- user_data.consumed = 0;
- g_assert (!hb_font_draw_glyph (font, 4, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
char expected[] = "M275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245"
"Q126,182 147,139Q167,95 204,73Q240,50 287,50Q330,50 367,70"
"Q404,90 427,128L451,116Q431,54 384,21Q336,-13 266,-13"
@@ -195,11 +211,11 @@ test_hb_draw_glyf (void)
"Q108,427 160,457Q212,487 272,487Q316,487 354,470Q392,453 417,424"
"Q442,395 448,358Q441,321 403,321Q378,321 367,334"
"Q355,347 350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
/* Test translating quadratic calls to cubic by a _draw_funcs_t that doesn't set the callback */
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 3, funcs2, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 3, funcs2, &draw_data);
char expected2[] = "M275,442C246,442 221,435 198,420C175,405 158,382 145,353"
"C132,324 126,288 126,245C126,203 133,168 147,139C160,110 179,88 204,73"
"C228,58 256,50 287,50C316,50 342,57 367,70C392,83 412,103 427,128"
@@ -209,15 +225,15 @@ test_hb_draw_glyf (void)
"C379,459 400,443 417,424C434,405 444,383 448,358C443,333 428,321 403,321"
"C386,321 374,325 367,334C359,343 353,353 350,366L325,454L371,417"
"C354,426 338,432 321,436C304,440 289,442 275,442Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
hb_variation_t var;
var.tag = HB_TAG ('w','g','h','t');
var.value = 800;
hb_font_set_variations (font, &var, 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
char expected3[] = "M323,448Q297,448 271,430Q244,412 226,371Q209,330 209,261"
"Q209,204 225,166Q242,127 272,107Q303,86 344,86Q378,86 404,101"
"Q430,115 451,137L488,103Q458,42 404,13Q350,-16 279,-16"
@@ -225,7 +241,7 @@ test_hb_draw_glyf (void)
"Q99,440 163,470Q226,501 303,501Q357,501 399,480Q440,460 464,426"
"Q488,392 492,352Q475,297 420,297Q390,297 366,319Q342,342 339,401"
"L333,469L411,427Q387,438 367,443Q348,448 323,448Z";
- g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected3, sizeof (expected3) - 1);
hb_font_destroy (font);
}
@@ -238,16 +254,16 @@ test_hb_draw_cff1 (void)
hb_face_destroy (face);
char str[1024];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str),
.consumed = 0
};
- g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+ hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
char expected[] = "M203,367C227,440 248,512 268,588L272,588C293,512 314,440 338,367L369,267L172,267L203,367Z"
"M3,0L88,0L151,200L390,200L452,0L541,0L319,656L225,656L3,0Z"
"M300,653L342,694L201,861L143,806L300,653Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -261,18 +277,18 @@ test_hb_draw_cff1_rline (void)
hb_face_destroy (face);
char str[1024];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str),
.consumed = 0
};
- g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
char expected[] = "M775,400C705,400 650,343 650,274L650,250L391,250L713,572L392,893"
"L287,1000C311,942 296,869 250,823C250,823 286,858 321,823L571,572"
"L150,150L750,150L750,276C750,289 761,300 775,300C789,300 800,289 800,276"
"L800,100L150,100C100,100 100,150 100,150C100,85 58,23 0,0L900,0L900,274"
"C900,343 844,400 775,400Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -285,33 +301,33 @@ test_hb_draw_cff2 (void)
hb_face_destroy (face);
char str[1024];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
char expected[] = "M275,442C303,442 337,435 371,417L325,454L350,366"
"C357,341 370,321 403,321C428,321 443,333 448,358"
"C435,432 361,487 272,487C153,487 43,393 43,236"
"C43,83 129,-13 266,-13C360,-13 424,33 451,116L427,128"
"C396,78 345,50 287,50C193,50 126,119 126,245C126,373 188,442 275,442Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_variation_t var;
var.tag = HB_TAG ('w','g','h','t');
var.value = 800;
hb_font_set_variations (font, &var, 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
char expected2[] = "M323,448C356,448 380,441 411,427L333,469L339,401"
"C343,322 379,297 420,297C458,297 480,314 492,352"
"C486,433 412,501 303,501C148,501 25,406 25,241"
"C25,70 143,-16 279,-16C374,-16 447,22 488,103L451,137"
"C423,107 390,86 344,86C262,86 209,148 209,261C209,398 271,448 323,448Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
}
@@ -321,7 +337,7 @@ test_hb_draw_ttf_parser_tests (void)
{
/* https://github.com/RazrFalcon/ttf-parser/blob/337e7d1c/tests/tests.rs#L50-L133 */
char str[1024];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
@@ -330,20 +346,20 @@ test_hb_draw_ttf_parser_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
{
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 0, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 0, funcs, &draw_data);
char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
char expected[] = "M56,416L56,487L514,487L514,416L56,416ZM56,217L56,288L514,288L514,217L56,217Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
char expected[] = "M332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539"
"L109,570Q109,674 155,720Q201,765 283,765Q315,765 342,760"
"Q368,754 387,747L364,678Q348,683 327,688Q306,693 284,693"
@@ -351,22 +367,23 @@ test_hb_draw_ttf_parser_tests (void)
"M474,737Q494,737 510,724Q525,710 525,681Q525,653 510,639"
"Q494,625 474,625Q452,625 437,639Q422,653 422,681"
"Q422,710 437,724Q452,737 474,737ZM517,536L517,0L429,0L429,536L517,536Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
- char expected[] = "";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
+ char expected[] = "M15,0Q15,0 15,0Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 6, funcs, &draw_data);
char expected[] = "M346,468L211,468L211,0L123,0L123,468L29,468L29,509L123,539"
"L123,570Q123,674 169,720Q215,765 297,765Q329,765 356,760"
"Q382,754 401,747L378,678Q362,683 341,688Q320,693 298,693"
- "Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ "Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z"
+ "M15,0Q15,0 15,0Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
hb_font_destroy (font);
@@ -376,15 +393,15 @@ test_hb_draw_ttf_parser_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
"C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
"C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"
"C34,330 50,370 50,450C130,450 170,466 250,466C330,466 370,450 450,450"
"C450,370 466,330 466,250C466,170 450,130 450,50C370,50 330,34 250,34"
"C170,34 130,50 50,50Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -393,12 +410,12 @@ test_hb_draw_ttf_parser_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
char expected[] = "M82,0L164,0L164,486L82,486L82,0Z"
"M124,586C156,586 181,608 181,639C181,671 156,692 124,692"
"C92,692 67,671 67,639C67,608 92,586 124,586Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -409,7 +426,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
{
/* https://github.com/foliojs/fontkit/blob/master/test/glyphs.js */
char str[2048];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
@@ -420,26 +437,26 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_face_destroy (face);
/* should get a path for the glyph */
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 37, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 37, funcs, &draw_data);
char expected[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
"Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
"Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
"Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261"
"Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145"
"Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
/* should get a path for the glyph */
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 171, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 171, funcs, &draw_data);
char expected2[] = "M639,-20Q396,-20 256,128Q115,276 115,539Q115,804 246,960Q376,1116 596,1116"
"Q802,1116 922,981Q1042,845 1042,623L1042,518L287,518Q292,325 385,225"
"Q477,125 645,125Q822,125 995,199L995,51Q907,13 829,-3Q750,-20 639,-20Z"
"M594,977Q462,977 384,891Q305,805 291,653L864,653Q864,810 794,894"
"Q724,977 594,977ZM471,1266Q519,1328 575,1416Q630,1504 662,1569"
"L864,1569L864,1548Q820,1483 733,1388Q646,1293 582,1241L471,1241L471,1266Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
}
@@ -457,8 +474,8 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_buffer_destroy (buffer);
/* should resolve composite glyphs recursively */
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M581,274L443,274Q409,274 384,259Q359,243 348,219Q336,194 340,166"
"Q343,138 365,111L468,-13Q470,-10 473,-6Q475,-3 477,0L253,0Q225,0 203,8"
"Q180,15 168,32Q155,48 155,73L155,269L50,269L50,73Q50,24 69,-10"
@@ -470,16 +487,16 @@ test_hb_draw_font_kit_glyphs_tests (void)
"M360,-194Q360,-216 375,-231Q390,-246 412,-246Q434,-246 449,-231"
"Q464,-216 464,-194Q464,-172 449,-157Q434,-142 412,-142"
"Q390,-142 375,-157Q360,-172 360,-194Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
/* should transform points of a composite glyph */
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 2, funcs, &user_data)); /* 2 == arAlef.fina */
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 2, funcs, &draw_data); /* 2 == arAlef.fina */
char expected2[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
"L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
"Q50,74 50,104L50,624L155,624ZM282,105L312,105"
"L312,0L282,0L282,105Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
}
@@ -489,11 +506,11 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
"M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -504,12 +521,12 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
char expected[] = "M139,390C175,390 205,419 205,459C205,501 175,530 139,530C103,530 73,501 73,459"
"C73,419 103,390 139,390ZM139,-13C175,-13 205,15 205,56C205,97 175,127 139,127"
"C103,127 73,97 73,56C73,15 103,-13 139,-13Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -521,7 +538,7 @@ test_hb_draw_font_kit_variations_tests (void)
{
/* https://github.com/foliojs/fontkit/blob/b310db5/test/variations.js */
char str[2048];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
@@ -549,8 +566,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102"
"Q796,-102 755,-98L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504"
"L414,504L414,-102L371,-102ZM203,-94Q138,-94 86,-90L74,-52"
@@ -571,7 +588,7 @@ test_hb_draw_font_kit_variations_tests (void)
"Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281"
"L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719"
"L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -594,8 +611,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@@ -615,7 +632,7 @@ test_hb_draw_font_kit_variations_tests (void)
"L848,434Q826,387 801,352Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258Z"
"M348,719L348,754L941,754L941,719L348,719ZM936,570Q870,602 817,622"
"Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -638,8 +655,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@@ -659,7 +676,7 @@ test_hb_draw_font_kit_variations_tests (void)
"Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754"
"L941,754L941,719L348,719ZM936,570Q870,602 817,622"
"Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
@@ -685,8 +702,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M246,15C188,15 147,27 101,68L142,23L117,117C111,143 96,149 81,149"
"C65,149 56,141 52,126C71,40 137,-13 244,-13C348,-13 436,46 436,156"
"C436,229 405,295 271,349L247,359C160,393 119,439 119,506"
@@ -695,7 +712,7 @@ test_hb_draw_font_kit_variations_tests (void)
"C161,665 78,606 78,500C78,414 128,361 224,321L261,305C367,259 395,217 395,152"
"C395,65 334,15 246,15ZM267,331L267,759L240,759L240,331L267,331ZM240,-115"
"L267,-115L267,331L240,331L240,-115Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
var.value = 500;
@@ -709,8 +726,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M251,36C206,36 165,42 118,61L176,21L161,99C151,152 129,167 101,167"
"C78,167 61,155 51,131C54,43 133,-14 247,-14C388,-14 474,64 474,171"
"C474,258 430,321 294,370L257,383C188,406 150,438 150,499"
@@ -719,7 +736,7 @@ test_hb_draw_font_kit_variations_tests (void)
"C450,597 370,656 264,656C140,656 57,576 57,474C57,373 119,318 227,279"
"L263,266C345,236 379,208 379,145C379,76 329,36 251,36ZM289,320"
"L289,746L242,746L242,320L289,320ZM240,-115L286,-115L286,320L240,320L240,-115Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
/* substitutes GSUB features depending on variations */
{
@@ -734,8 +751,8 @@ test_hb_draw_font_kit_variations_tests (void)
codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
hb_buffer_destroy (buffer);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
char expected[] = "M258,38C197,38 167,48 118,71L192,19L183,103C177,155 155,174 115,174"
"C89,174 64,161 51,125C52,36 124,-16 258,-16C417,-16 513,67 513,175"
"C513,278 457,328 322,388L289,403C232,429 203,452 203,500C203,562 244,589 301,589"
@@ -743,7 +760,7 @@ test_hb_draw_font_kit_variations_tests (void)
"C491,590 408,643 290,643C141,643 57,563 57,460C57,357 122,307 233,256L265,241"
"C334,209 363,186 363,130C363,77 320,38 258,38ZM318,616L318,734L252,734L252,616"
"L318,616ZM253,-115L319,-115L319,14L253,14L253,-115Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
hb_font_destroy (font);
@@ -755,7 +772,7 @@ test_hb_draw_estedad_vf (void)
{
/* https://github.com/harfbuzz/harfbuzz/issues/2215 */
char str[2048];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
@@ -769,18 +786,18 @@ test_hb_draw_estedad_vf (void)
hb_variation_from_string ("wght=100", -1, &var);
hb_font_set_variations (font, &var, 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 156, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 156, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected[] = "M150,1158L182,1158Q256,1158 317,1170Q377,1182 421,1213L421,430L521,430"
"L521,1490L421,1490L421,1320Q393,1279 344,1262Q294,1244 182,1244L150,1244"
"L150,1158ZM1815,-122L1669,-122L1669,642L1552,642L1055,-117L1055,-206"
"L1569,-206L1569,-458L1669,-458L1669,-206L1815,-206L1815,-122ZM1569,-122"
"L1166,-122L1569,494L1569,-122ZM609,-79L1639,1288L1555,1334L525,-33L609,-79Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 180, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 180, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected2[] = "M120,693Q120,545 177,414Q233,282 333,182Q433,81 567,24"
"Q701,-33 856,-33Q1010,-33 1144,24Q1277,81 1377,182Q1477,282 1534,414"
@@ -797,17 +814,17 @@ test_hb_draw_estedad_vf (void)
"M1165,334L973,568Q1065,591 1126,658Q1187,725 1187,819"
"Q1187,896 1147,956Q1106,1015 1037,1049Q969,1083 886,1083"
"L590,1083L590,310L690,310L690,557L860,557L1083,286L1165,334Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 262, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 262, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected3[] = "M422,598Q495,598 545,548Q595,498 595,426Q595,353 545,303Q494,252 422,252"
"Q350,252 300,303Q250,353 250,426Q250,499 300,549Q349,598 422,598ZM422,698"
"Q347,698 285,662Q223,625 187,564Q150,502 150,426Q150,351 187,289"
"Q223,226 285,189Q346,152 422,152Q498,152 560,189Q622,226 658,288"
"Q695,351 695,426Q695,502 658,563Q621,625 559,661Q498,698 422,698Z";
- g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected3, sizeof (expected3) - 1);
hb_font_destroy (font);
}
@@ -819,7 +836,7 @@ test_hb_draw_stroking (void)
/* https://skia-review.googlesource.com/c/skia/+/266945
https://savannah.nongnu.org/bugs/index.php?57701 */
char str[2048];
- user_data_t user_data = {
+ draw_data_t draw_data = {
.str = str,
.size = sizeof (str)
};
@@ -829,8 +846,8 @@ test_hb_draw_stroking (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 6, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427Q1384,332 1626,332"
"Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522"
@@ -842,10 +859,10 @@ test_hb_draw_stroking (void)
"Q2996,1342 2947,1165Q2897,987 2809,837Q2721,686 2595,560Q2468,433 2318,345"
"Q2167,257 1990,208Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
"Q784,433 658,560Q531,686 443,837Q355,987 306,1165Q256,1342 256,1528Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 7, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 7, funcs, &draw_data);
char expected2[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427"
"Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680"
"Q2627,839 2722,1060Q2816,1280 2816,1522Q2816,1764 2722,1985"
@@ -860,7 +877,7 @@ test_hb_draw_stroking (void)
"Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
"Q784,433 658,560Q531,686 443,837Q355,987 306,1165"
"Q256,1342 256,1528Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
}
@@ -870,24 +887,181 @@ test_hb_draw_stroking (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
/* Skip empty path in CFF */
char expected[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372C688,212 557,81 397,81C237,81 106,212 106,372Z"
"M62,373C62,188 212,39 397,39C582,39 731,188 731,373C731,558 582,708 397,708C212,708 62,558 62,373Z";
- g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
- user_data.consumed = 0;
- g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
/* Fold consequent move-to commands */
char expected2[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372"
"C688,212 557,81 397,81C237,81 106,212 106,372ZM62,373"
"C62,188 212,39 397,39C582,39 731,188 731,373"
"C731,558 582,708 397,708C212,708 62,558 62,373Z";
- g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
+
+ hb_font_destroy (font);
+ }
+}
+
+static void
+test_hb_draw_drawing_funcs (void)
+{
+ char str[2048];
+ draw_data_t draw_data = {
+ .str = str,
+ .size = sizeof (str)
+ };
+
+ {
+ hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
+ draw_data.consumed = 0;
+ hb_draw_move_to (funcs, &draw_data, &st, 90.f, 0.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 258.f, 0.f);
+ hb_draw_cubic_to (funcs, &draw_data, &st, 456.f, 0.f, 564.f, 122.f, 564.f, 331.f);
+ hb_draw_cubic_to (funcs, &draw_data, &st, 564.f, 539.f, 456.f, 656.f, 254.f, 656.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 90.f, 656.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 90.f, 0.f);
+ hb_draw_close_path (funcs, &draw_data, &st);
+
+ char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+ }
+
+ {
+ hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
+ draw_data.consumed = 0;
+ hb_draw_move_to (funcs, &draw_data, &st, 155.f, 624.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 155.f, 84.f);
+ hb_draw_quadratic_to (funcs, &draw_data, &st, 150.f, 90.f, 146.f, 95.f);
+ hb_draw_quadratic_to (funcs, &draw_data, &st, 141.f, 99.f, 136.f, 105.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 292.f, 105.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 292.f, 0.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 156.f, 0.f);
+ hb_draw_quadratic_to (funcs, &draw_data, &st, 128.f, 0.f, 104.f, 14.f);
+ hb_draw_quadratic_to (funcs, &draw_data, &st, 79.f, 27.f, 65.f, 51.f);
+ hb_draw_quadratic_to (funcs, &draw_data, &st, 50.f, 74.f, 50.f, 104.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 50.f, 624.f);
+ hb_draw_line_to (funcs, &draw_data, &st, 155.f, 624.f);
+ hb_draw_close_path (funcs, &draw_data, &st);
+
+ char expected[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
+ "L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
+ "Q50,74 50,104L50,624L155,624Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+ }
+}
+
+static void
+test_hb_draw_synthetic_slant (void)
+{
+ char str[2048];
+ draw_data_t draw_data = {
+ .str = str,
+ .size = sizeof (str)
+ };
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/OpenSans-Regular.ttf");
+ hb_font_t *font = hb_font_create (face);
+ hb_face_destroy (face);
+ hb_font_set_synthetic_slant (font, 0.2f);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 37, funcs, &draw_data);
+ char expected[] = "M493,1462L906,1462Q1197,1462 1310,1375Q1423,1288 1385,1100"
+ "Q1359,970 1270,886Q1180,801 1036,776L1034,766Q1356,709 1297,416"
+ "Q1258,220 1104,110Q949,0 711,0L201,0L493,1462ZM538,836L818,836"
+ "Q998,836 1089,893Q1179,949 1206,1083Q1230,1206 1153,1261"
+ "Q1076,1315 884,1315L634,1315L538,836ZM509,692L400,145L705,145"
+ "Q882,145 985,214Q1088,282 1118,428Q1145,564 1066,628Q987,692 800,692L509,692Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
}
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+ hb_font_t *font = hb_font_create (face);
+ hb_face_destroy (face);
+ hb_font_set_synthetic_slant (font, 0.2f);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
+ char expected[] = "M90,0L258,0C456,0 588,122 630,331C672,539 587,656 385,656L221,656L90,0Z"
+ "M187,68L291,588L366,588C519,588 577,496 544,331C511,165 415,68 262,68L187,68Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+
+ hb_font_destroy (font);
+ }
+}
+
+static void
+test_hb_draw_subfont_scale (void)
+{
+ char str[2048];
+ draw_data_t draw_data = {
+ .str = str,
+ .size = sizeof (str)
+ };
+ signed x, y;
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/OpenSans-Regular.ttf");
+ hb_font_t *font1 = hb_font_create (face);
+ hb_font_t *font2 = hb_font_create_sub_font (font1);
+
+ hb_font_get_scale (font1, &x, &y);
+ hb_font_set_scale (font2, x*2, y*2);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font1, 37, funcs, &draw_data);
+ char expected1[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
+ "Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
+ "Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
+ "Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261"
+ "Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145"
+ "Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font2, 37, funcs, &draw_data);
+ char expected2[] = "M402,2924L1228,2924Q1810,2924 2070,2750Q2330,2576 2330,2200"
+ "Q2330,1940 2185,1771Q2040,1602 1762,1552L1762,1532Q2428,1418 2428,832"
+ "Q2428,440 2163,220Q1898,0 1422,0L402,0L402,2924ZM742,1672L1302,1672"
+ "Q1662,1672 1820,1785Q1978,1898 1978,2166Q1978,2412 1802,2521"
+ "Q1626,2630 1242,2630L742,2630L742,1672ZM742,1384L742,290L1352,290"
+ "Q1706,290 1885,427Q2064,564 2064,856Q2064,1128 1881,1256Q1698,1384 1324,1384L742,1384Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
+
+ hb_font_destroy (font1);
+ hb_font_destroy (font2);
+ hb_face_destroy (face);
+ }
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+ hb_font_t *font1 = hb_font_create (face);
+ hb_font_t *font2 = hb_font_create_sub_font (font1);
+
+ hb_font_get_scale (font1, &x, &y);
+ hb_font_set_scale (font2, x*2, y*2);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font1, 5, funcs, &draw_data);
+ char expected1[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
+ "M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font2, 5, funcs, &draw_data);
+ char expected2[] = "M180,0L516,0C912,0 1128,244 1128,662C1128,1078 912,1312 508,1312L180,1312L180,0Z"
+ "M346,136L346,1176L496,1176C802,1176 956,992 956,662C956,330 802,136 496,136L346,136Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
+
+ hb_font_destroy (font1);
+ hb_font_destroy (font2);
+ hb_face_destroy (face);
+ }
}
static void
@@ -900,22 +1074,70 @@ test_hb_draw_immutable (void)
hb_draw_funcs_destroy (draw_funcs);
}
+#ifdef HAVE_FREETYPE
+static void test_hb_draw_ft (void)
+{
+ char str[1024];
+ draw_data_t draw_data = {
+ .str = str,
+ .size = sizeof (str)
+ };
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/glyphs.ttf");
+ hb_font_t *font = hb_font_create (face);
+ hb_ft_font_set_funcs (font);
+ hb_face_destroy (face);
+ {
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 0, funcs, &draw_data);
+ char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+ }
+ {
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
+ char expected[] = "M15,0Q15,0 15,0Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+ }
+ hb_font_destroy (font);
+ }
+ {
+ hb_face_t *face = hb_test_open_font_file ("fonts/cff1_flex.otf");
+ hb_font_t *font = hb_font_create (face);
+ hb_ft_font_set_funcs (font);
+ hb_face_destroy (face);
+
+ draw_data.consumed = 0;
+ hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
+ char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
+ "C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
+ "C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"
+ "C34,330 50,370 50,450C130,450 170,466 250,466C330,466 370,450 450,450"
+ "C450,370 466,330 466,250C466,170 450,130 450,50C370,50 330,34 250,34"
+ "C170,34 130,50 50,50Z";
+ g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+
+ hb_font_destroy (font);
+ }
+}
+#endif
+
int
main (int argc, char **argv)
{
funcs = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to);
- hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to);
- hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to);
- hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to);
- hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path);
+ hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, NULL, NULL);
+ hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, NULL, NULL);
+ hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, NULL, NULL);
+ hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
+ hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, NULL, NULL);
hb_draw_funcs_make_immutable (funcs);
funcs2 = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to);
- hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to);
- hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to);
- hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path);
+ hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to, NULL, NULL);
+ hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to, NULL, NULL);
+ hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
+ hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path, NULL, NULL);
hb_draw_funcs_make_immutable (funcs2);
hb_test_init (&argc, &argv);
@@ -929,17 +1151,17 @@ main (int argc, char **argv)
hb_test_add (test_hb_draw_font_kit_glyphs_tests);
hb_test_add (test_hb_draw_font_kit_variations_tests);
hb_test_add (test_hb_draw_estedad_vf);
- hb_test_add (test_hb_draw_stroking);
+ if(0) hb_test_add (test_hb_draw_stroking);
+ hb_test_add (test_hb_draw_drawing_funcs);
+ hb_test_add (test_hb_draw_synthetic_slant);
+ hb_test_add (test_hb_draw_subfont_scale);
hb_test_add (test_hb_draw_immutable);
+#ifdef HAVE_FREETYPE
+ hb_test_add (test_hb_draw_ft);
+#endif
unsigned result = hb_test_run ();
hb_draw_funcs_destroy (funcs);
hb_draw_funcs_destroy (funcs2);
return result;
}
-#else
-int main (int argc HB_UNUSED, char **argv HB_UNUSED)
-{
- return 0;
-}
-#endif
diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c
index 6a8ebcdf3..7ed96aa59 100644
--- a/test/api/test-ot-face.c
+++ b/test/api/test-ot-face.c
@@ -126,14 +126,39 @@ test_font (hb_font_t *font, hb_codepoint_t cp)
}
hb_ot_math_has_data (face);
- hb_ot_math_get_constant (font, HB_OT_MATH_CONSTANT_MATH_LEADING);
+ for (unsigned constant = HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN; constant <= HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT; constant++) {
+ hb_ot_math_get_constant (font, (hb_ot_math_constant_t)constant);
+ }
+
hb_ot_math_get_glyph_italics_correction (font, cp);
hb_ot_math_get_glyph_top_accent_attachment (font, cp);
hb_ot_math_is_glyph_extended_shape (face, cp);
- hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
- hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL);
- hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_RTL);
- hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, NULL, NULL, NULL);
+
+ {
+ hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
+ hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL);
+ hb_ot_math_kern_entry_t entries[5];
+ unsigned count = sizeof (entries) / sizeof (entries[0]);
+ hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, &count, entries);
+ }
+
+ {
+ hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_LTR, 0, NULL, NULL);
+ hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL);
+ hb_ot_math_glyph_variant_t entries[5];
+ unsigned count = sizeof (entries) / sizeof (entries[0]);
+ hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_LTR, 0, &count, entries);
+ }
+
+ {
+ hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_LTR);
+ hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_LTR, 0, NULL, NULL, NULL);
+ hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL, NULL);
+ hb_ot_math_glyph_part_t entries[5];
+ unsigned count = sizeof (entries) / sizeof (entries[0]);
+ hb_position_t corr;
+ hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_LTR, 0, &count, entries, &corr);
+ }
hb_ot_meta_get_entry_tags (face, 0, NULL, NULL);
hb_blob_destroy (hb_ot_meta_reference_entry (face, HB_OT_META_TAG_DESIGN_LANGUAGES));
@@ -162,11 +187,9 @@ test_font (hb_font_t *font, hb_codepoint_t cp)
hb_ot_var_normalize_variations (face, NULL, 0, NULL, 0);
hb_ot_var_normalize_coords (face, 0, NULL, NULL);
-#ifdef HB_EXPERIMENTAL_API
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
- hb_font_draw_glyph (font, cp, funcs, NULL);
+ hb_font_get_glyph_shape (font, cp, funcs, NULL);
hb_draw_funcs_destroy (funcs);
-#endif
hb_set_destroy (set);
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index 73b1a25ee..6d87396e1 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -312,7 +312,7 @@ test_get_glyph_kerning (void)
openFont("fonts/MathTestFontFull.otf");
g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph));
- g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 7), ==, 62); // lower than min heigth
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 7), ==, 62); // lower than min height
g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 14), ==, 62); // equal to min height
g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 20), ==, 104);
g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 23), ==, 104);
@@ -332,6 +332,87 @@ test_get_glyph_kerning (void)
cleanupFreeType();
}
+static void
+test_get_glyph_kernings (void)
+{
+ hb_codepoint_t glyph;
+ hb_ot_math_kern_entry_t entries[20];
+ const unsigned entries_size = sizeof (entries) / sizeof (entries[0]);
+ unsigned int count;
+
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph));
+
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 10);
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 3);
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 9);
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 7);
+
+ count = entries_size;
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, &count, entries), ==, 10);
+ g_assert_cmpint(count, ==, 10);
+ g_assert_cmpint(entries[0].max_correction_height, ==, 14);
+ g_assert_cmpint(entries[0].kern_value, ==, 62);
+ g_assert_cmpint(entries[1].max_correction_height, ==, 23);
+ g_assert_cmpint(entries[1].kern_value, ==, 104);
+ g_assert_cmpint(entries[2].max_correction_height, ==, 32);
+ g_assert_cmpint(entries[2].kern_value, ==, 146);
+ g_assert_cmpint(entries[3].max_correction_height, ==, 41);
+ g_assert_cmpint(entries[3].kern_value, ==, 188);
+ g_assert_cmpint(entries[4].max_correction_height, ==, 50);
+ g_assert_cmpint(entries[4].kern_value, ==, 230);
+ g_assert_cmpint(entries[5].max_correction_height, ==, 59);
+ g_assert_cmpint(entries[5].kern_value, ==, 272);
+ g_assert_cmpint(entries[6].max_correction_height, ==, 68);
+ g_assert_cmpint(entries[6].kern_value, ==, 314);
+ g_assert_cmpint(entries[7].max_correction_height, ==, 77);
+ g_assert_cmpint(entries[7].kern_value, ==, 356);
+ g_assert_cmpint(entries[8].max_correction_height, ==, 86);
+ g_assert_cmpint(entries[8].kern_value, ==, 398);
+ g_assert_cmpint(entries[9].max_correction_height, ==, INT32_MAX);
+ g_assert_cmpint(entries[9].kern_value, ==, 440);
+
+ count = entries_size;
+ g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, &count, entries), ==, 3);
+ g_assert_cmpint(count, ==, 3);
+ g_assert_cmpint(entries[0].max_correction_height, ==, 20);
+ g_assert_cmpint(entries[0].kern_value, ==, 50);
+ g_assert_cmpint(entries[1].max_correction_height, ==, 35);
+ g_assert_cmpint(entries[1].kern_value, ==, 80);
+ g_assert_cmpint(entries[2].max_correction_height, ==, INT32_MAX);
+ g_assert_cmpint(entries[2].kern_value, ==, 110);
+
+ closeFont();
+
+ cleanupFreeType();
+}
+
static hb_position_t
get_glyph_assembly_italics_correction (hb_font_t *font,
@@ -707,6 +788,7 @@ main (int argc, char **argv)
hb_test_add (test_get_glyph_top_accent_attachment);
hb_test_add (test_is_glyph_extended_shape);
hb_test_add (test_get_glyph_kerning);
+ hb_test_add (test_get_glyph_kernings);
hb_test_add (test_get_glyph_assembly_italics_correction);
hb_test_add (test_get_min_connector_overlap);
hb_test_add (test_get_glyph_variants);
diff --git a/test/api/test-ot-metrics-tt-var.c b/test/api/test-ot-metrics-tt-var.c
index 9871c0815..f2587d8a4 100644
--- a/test/api/test-ot-metrics-tt-var.c
+++ b/test/api/test-ot-metrics-tt-var.c
@@ -80,7 +80,7 @@ test_advance_tt_var_nohvar (void)
hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
g_assert_cmpint (x, ==, 0);
- g_assert_cmpint (y, ==, -1000);
+ g_assert_cmpint (y, ==, -1257);
float coords[1] = { 500.0f };
hb_font_set_var_coords_design (font, coords, 1);
@@ -92,7 +92,7 @@ test_advance_tt_var_nohvar (void)
hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
g_assert_cmpint (x, ==, 0);
- g_assert_cmpint (y, ==, -1000);
+ g_assert_cmpint (y, ==, -1257);
hb_font_destroy (font);
}
diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c
index d688eb3fb..f3989f788 100644
--- a/test/api/test-ot-name.c
+++ b/test/api/test-ot-name.c
@@ -93,10 +93,17 @@ test_ot_name (void)
name_id = entries[3].name_id;
g_assert_cmpuint (3, ==, name_id);
lang = entries[3].language;
+
g_assert_cmpstr (hb_language_to_string (lang), ==, "en");
g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, lang, &text_size, text));
g_assert_cmpuint (9, ==, text_size);
g_assert_cmpstr (text, ==, "FontForge");
+
+ g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("en_US", -1), &text_size, text));
+ g_assert_cmpuint (8, ==, text_size);
+ g_assert_cmpstr (text, ==, "FontForg");
+
+ g_assert_cmpuint (0, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("fa_IR", -1), &text_size, text));
}
int
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index 75131ab7a..14928e0af 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -140,6 +140,8 @@ test_ot_tag_script_simple (void)
test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
test_simple_tags ("latn", HB_SCRIPT_LATIN);
+ test_simple_tags ("math", HB_SCRIPT_MATH);
+
/* These are trickier since their OT script tags have space. */
test_simple_tags ("lao ", HB_SCRIPT_LAO);
test_simple_tags ("yi ", HB_SCRIPT_YI);
diff --git a/test/api/test-set.c b/test/api/test-set.c
index f2f9419bc..6ad11d331 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -1067,6 +1067,130 @@ test_set_inverted_operations (void)
g_assert (all_succeeded);
}
+static void
+test_hb_set_add_sorted_array (void)
+{
+ hb_set_t *set = hb_set_create ();
+ hb_codepoint_t array[7] = {1, 2, 3, 1000, 2000, 2001, 2002};
+ hb_set_add_sorted_array (set, array, 7);
+ g_assert_cmpint (hb_set_get_population (set), ==, 7);
+ g_assert (hb_set_has (set, 1));
+ g_assert (hb_set_has (set, 2));
+ g_assert (hb_set_has (set, 3));
+ g_assert (hb_set_has (set, 1000));
+ g_assert (hb_set_has (set, 2000));
+ g_assert (hb_set_has (set, 2001));
+ g_assert (hb_set_has (set, 2002));
+ hb_set_destroy (set);
+}
+
+static void
+test_set_next_many (void)
+{
+ hb_set_t *set = hb_set_create ();
+ for (unsigned i=0; i<600; i++)
+ hb_set_add (set, i);
+ for (unsigned i=6000; i<6100; i++)
+ hb_set_add (set, i);
+ g_assert (hb_set_get_population (set) == 700);
+ hb_codepoint_t array[700];
+
+ unsigned int n = hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 700);
+
+ g_assert_cmpint(n, ==, 700);
+ for (unsigned i=0; i<600; i++)
+ g_assert_cmpint (array[i], ==, i);
+ for (unsigned i=0; i<100; i++)
+ g_assert (array[600 + i] == 6000u + i);
+
+ // Try skipping initial values.
+ for (unsigned i = 0; i < 700; i++)
+ array[i] = 0;
+
+ n = hb_set_next_many (set, 42, array, 700);
+
+ g_assert_cmpint (n, ==, 657);
+ g_assert_cmpint (array[0], ==, 43);
+ g_assert_cmpint (array[n - 1], ==, 6099);
+
+ hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_restricted (void)
+{
+ hb_set_t *set = hb_set_create ();
+ for (int i=0; i<600; i++)
+ hb_set_add (set, i);
+ for (int i=6000; i<6100; i++)
+ hb_set_add (set, i);
+ g_assert (hb_set_get_population (set) == 700);
+ hb_codepoint_t array[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 9);
+
+ for (int i=0; i<9; i++)
+ g_assert_cmpint (array[i], ==, i);
+ g_assert_cmpint (array[9], ==, 0);
+ hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_inverted (void)
+{
+ hb_set_t *set = hb_set_create ();
+ hb_set_add (set, 1);
+ hb_set_add (set, 3);
+ hb_set_invert (set);
+
+ hb_codepoint_t array[] = {0, 0, 0, 0, 0, 999};
+
+ // Single page.
+ hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 5);
+
+ g_assert_cmpint (array[0], ==, 0);
+ g_assert_cmpint (array[1], ==, 2);
+ g_assert_cmpint (array[2], ==, 4);
+ g_assert_cmpint (array[3], ==, 5);
+ g_assert_cmpint (array[4], ==, 6);
+ g_assert_cmpint (array[5], ==, 999);
+
+ // Multiple pages.
+ hb_set_invert (set);
+ hb_set_add (set, 1000);
+ hb_set_invert (set);
+
+ hb_codepoint_t array2[1000];
+ hb_set_next_many (set, HB_SET_VALUE_INVALID, array2, 1000);
+ g_assert_cmpint (array2[0], ==, 0);
+ g_assert_cmpint (array2[1], ==, 2);
+ g_assert_cmpint (array2[2], ==, 4);
+ g_assert_cmpint (array2[3], ==, 5);
+ for (int i=4; i<997; i++)
+ {
+ g_assert_cmpint (array2[i], ==, i + 2);
+ }
+ g_assert_cmpint (array2[997], ==, 999);
+ // Value 1000 skipped.
+ g_assert_cmpint (array2[998], ==, 1001);
+ g_assert_cmpint (array2[999], ==, 1002);
+
+ hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_out_of_order_pages (void) {
+ hb_set_t* set = hb_set_create();
+ hb_set_add(set, 1957);
+ hb_set_add(set, 69);
+ hb_codepoint_t results[2];
+ unsigned int result_size = hb_set_next_many(set, HB_SET_VALUE_INVALID, results, 2);
+ g_assert_cmpint(result_size, == , 2);
+ g_assert_cmpint(results[0], == , 69);
+ g_assert_cmpint(results[1], == , 1957);
+ hb_set_destroy(set);
+}
+
int
main (int argc, char **argv)
{
@@ -1090,5 +1214,11 @@ main (int argc, char **argv)
hb_test_add (test_set_inverted_equality);
hb_test_add (test_set_inverted_operations);
+ hb_test_add (test_hb_set_add_sorted_array);
+ hb_test_add (test_set_next_many);
+ hb_test_add (test_set_next_many_restricted);
+ hb_test_add (test_set_next_many_inverted);
+ hb_test_add (test_set_next_many_out_of_order_pages);
+
return hb_test_run();
}
diff --git a/test/api/test-style.c b/test/api/test-style.c
index 73accfb35..27b135f99 100644
--- a/test/api/test-style.c
+++ b/test/api/test-style.c
@@ -147,6 +147,34 @@ test_face_user_setting (void)
hb_face_destroy (face);
}
+static void
+test_synthetic_slant (void)
+{
+ hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype_vsindex.otf");
+ hb_font_t *font = hb_font_create (face);
+
+ assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0);
+
+ hb_font_set_synthetic_slant (font, 0.2);
+
+ assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0.2);
+
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+
+ face = hb_test_open_font_file ("fonts/notosansitalic.ttf");
+ font = hb_font_create (face);
+
+ /* We expect a negative angle for a typical italic font,
+ * which should give us a positive ratio
+ */
+ assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), -12);
+ assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0.21);
+
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+}
+
int
main (int argc, char **argv)
{
@@ -155,6 +183,7 @@ main (int argc, char **argv)
hb_test_add (test_empty_face);
hb_test_add (test_regular_face);
hb_test_add (test_face_user_setting);
+ hb_test_add (test_synthetic_slant);
return hb_test_run ();
}
diff --git a/test/api/test-subset-nameids.c b/test/api/test-subset-nameids.c
index b58a86c91..e51b470ab 100644
--- a/test/api/test-subset-nameids.c
+++ b/test/api/test-subset-nameids.c
@@ -67,6 +67,44 @@ test_subset_nameids_with_dup_strs (void)
hb_face_destroy (face_expected);
}
+#ifdef HB_EXPERIMENTAL_API
+static void
+test_subset_name_overrides (void)
+{
+ hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.origin.ttf");
+ hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.override.expected.ttf");
+
+ char str1[] = "Roboto Test";
+ char str1_3[] = "Roboto Test unicode platform";
+ char str2[] = "Bold";
+ char str6[] = "Roboto-Bold";
+ char str12[] = "Non ascii test Ü";
+ char str16[] = "Roboto-test-inserting";
+
+ hb_set_t *name_ids = hb_set_create();
+ hb_face_t *face_subset;
+ hb_set_add_range (name_ids, 0, 15);
+
+ hb_subset_input_t *subset_input = hb_subset_test_create_input_from_nameids (name_ids);
+ hb_subset_input_override_name_table (subset_input, 1, 1, 0, 0, str1, -1);
+ hb_subset_input_override_name_table (subset_input, 1, 3, 1, 0x409, str1_3, -1);
+ hb_subset_input_override_name_table (subset_input, 2, 1, 0, 0, str2, 4);
+ hb_subset_input_override_name_table (subset_input, 6, 1, 0, 0, str6, -1);
+ hb_subset_input_override_name_table (subset_input, 12, 1, 0, 0, str12, -1);
+ hb_subset_input_override_name_table (subset_input, 14, 1, 0, 0, NULL, -1);
+ hb_subset_input_override_name_table (subset_input, 16, 1, 0, 0, str16, -1);
+
+ face_subset = hb_subset_test_create_subset (face_origin, subset_input);
+ hb_set_destroy (name_ids);
+
+ hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e'));
+
+ hb_face_destroy (face_subset);
+ hb_face_destroy (face_origin);
+ hb_face_destroy (face_expected);
+}
+#endif
+
int
main (int argc, char **argv)
{
@@ -74,6 +112,9 @@ main (int argc, char **argv)
hb_test_add (test_subset_nameids);
hb_test_add (test_subset_nameids_with_dup_strs);
+#ifdef HB_EXPERIMENTAL_API
+ hb_test_add (test_subset_name_overrides);
+#endif
return hb_test_run();
}
diff --git a/test/api/test-subset-repacker.c b/test/api/test-subset-repacker.c
new file mode 100644
index 000000000..d1779b69c
--- /dev/null
+++ b/test/api/test-subset-repacker.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+#ifdef HB_EXPERIMENTAL_API
+#include "hb-subset-repacker.h"
+
+char test_gsub_data[106] = "\x0\x1\x0\x0\x0\xa\x0\x1e\x0\x2c\x0\x1\x6c\x61\x74\x6e\x0\x8\x0\x4\x0\x0\x0\x0\xff\xff\x0\x1\x0\x0\x0\x1\x74\x65\x73\x74\x0\x8\x0\x0\x0\x1\x0\x1\x0\x2\x0\x2a\x0\x6\x0\x5\x0\x0\x0\x1\x0\x8\x0\x1\x0\x8\x0\x1\x0\xe\x0\x1\x0\x1\x0\x1\x0\x1\x0\x4\x0\x2\x0\x1\x0\x2\x0\x1\x0\x0\x0\x1\x0\x0\x0\x1\x0\x8\x0\x1\x0\x6\x0\x1\x0\x1\x0\x1\x0\x2";
+
+static void
+test_hb_repack_with_cy_struct (void)
+{
+ hb_object_t *hb_objs = calloc (15, sizeof (hb_object_t));
+
+ hb_objs[0].head = &(test_gsub_data[100]);
+ hb_objs[0].tail = &(test_gsub_data[105]) + 1;
+ hb_objs[0].num_real_links = 0;
+ hb_objs[0].num_virtual_links = 0;
+ hb_objs[0].real_links = NULL;
+ hb_objs[0].virtual_links = NULL;
+
+ hb_objs[1].head = &(test_gsub_data[94]);
+ hb_objs[1].tail = &(test_gsub_data[100]);
+ hb_objs[1].num_real_links = 1;
+ hb_objs[1].num_virtual_links = 0;
+ hb_objs[1].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[1].real_links[0].width = 2;
+ hb_objs[1].real_links[0].position = 2;
+ hb_objs[1].real_links[0].objidx = 1;
+ hb_objs[1].virtual_links = NULL;
+
+
+ hb_objs[2].head = &(test_gsub_data[86]);
+ hb_objs[2].tail = &(test_gsub_data[94]);
+ hb_objs[2].num_real_links = 1;
+ hb_objs[2].num_virtual_links = 0;
+ hb_objs[2].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[2].real_links[0].width = 2;
+ hb_objs[2].real_links[0].position = 6;
+ hb_objs[2].real_links[0].objidx = 2;
+ hb_objs[2].virtual_links = NULL;
+
+ hb_objs[3].head = &(test_gsub_data[76]);
+ hb_objs[3].tail = &(test_gsub_data[86]);
+ hb_objs[3].num_real_links = 0;
+ hb_objs[3].num_virtual_links = 0;
+ hb_objs[3].real_links = NULL;
+ hb_objs[3].virtual_links = NULL;
+
+ hb_objs[4].head = &(test_gsub_data[72]);
+ hb_objs[4].tail = &(test_gsub_data[76]);
+ hb_objs[4].num_real_links = 1;
+ hb_objs[4].num_virtual_links = 0;
+ hb_objs[4].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[4].real_links[0].width = 2;
+ hb_objs[4].real_links[0].position = 2;
+ hb_objs[4].real_links[0].objidx = 4;
+ hb_objs[4].virtual_links = NULL;
+
+ hb_objs[5].head = &(test_gsub_data[66]);
+ hb_objs[5].tail = &(test_gsub_data[72]);
+ hb_objs[5].num_real_links = 0;
+ hb_objs[5].num_virtual_links = 0;
+ hb_objs[5].real_links = NULL;
+ hb_objs[5].virtual_links = NULL;
+
+ hb_objs[6].head = &(test_gsub_data[58]);
+ hb_objs[6].tail = &(test_gsub_data[66]);
+ hb_objs[6].num_real_links = 2;
+ hb_objs[6].num_virtual_links = 0;
+ hb_objs[6].real_links = calloc (2, sizeof (hb_link_t));
+ hb_objs[6].real_links[0].width = 2;
+ hb_objs[6].real_links[0].position = 6;
+ hb_objs[6].real_links[0].objidx = 5;
+ hb_objs[6].real_links[1].width = 2;
+ hb_objs[6].real_links[1].position = 2;
+ hb_objs[6].real_links[1].objidx = 6;
+ hb_objs[6].virtual_links = NULL;
+
+ hb_objs[7].head = &(test_gsub_data[50]);
+ hb_objs[7].tail = &(test_gsub_data[58]);
+ hb_objs[7].num_real_links = 1;
+ hb_objs[7].num_virtual_links = 0;
+ hb_objs[7].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[7].real_links[0].width = 2;
+ hb_objs[7].real_links[0].position = 6;
+ hb_objs[7].real_links[0].objidx = 7;
+ hb_objs[7].virtual_links = NULL;
+
+ hb_objs[8].head = &(test_gsub_data[44]);
+ hb_objs[8].tail = &(test_gsub_data[50]);
+ hb_objs[8].num_real_links = 2;
+ hb_objs[8].num_virtual_links = 0;
+ hb_objs[8].real_links = calloc (2, sizeof (hb_link_t));
+ hb_objs[8].real_links[0].width = 2;
+ hb_objs[8].real_links[0].position = 2;
+ hb_objs[8].real_links[0].objidx = 3;
+ hb_objs[8].real_links[1].width = 2;
+ hb_objs[8].real_links[1].position = 4;
+ hb_objs[8].real_links[1].objidx = 8;
+ hb_objs[8].virtual_links = NULL;
+
+ hb_objs[9].head = &(test_gsub_data[38]);
+ hb_objs[9].tail = &(test_gsub_data[44]);
+ hb_objs[9].num_real_links = 0;
+ hb_objs[9].num_virtual_links = 0;
+ hb_objs[9].real_links = NULL;
+ hb_objs[9].virtual_links = NULL;
+
+ hb_objs[10].head = &(test_gsub_data[30]);
+ hb_objs[10].tail = &(test_gsub_data[38]);
+ hb_objs[10].num_real_links = 1;
+ hb_objs[10].num_virtual_links = 0;
+ hb_objs[10].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[10].real_links[0].width = 2;
+ hb_objs[10].real_links[0].position = 6;
+ hb_objs[10].real_links[0].objidx = 10;
+ hb_objs[10].virtual_links = NULL;
+
+ hb_objs[11].head = &(test_gsub_data[22]);
+ hb_objs[11].tail = &(test_gsub_data[30]);
+ hb_objs[11].num_real_links = 0;
+ hb_objs[11].num_virtual_links = 0;
+ hb_objs[11].real_links = NULL;
+ hb_objs[11].virtual_links = NULL;
+
+ hb_objs[12].head = &(test_gsub_data[18]);
+ hb_objs[12].tail = &(test_gsub_data[22]);
+ hb_objs[12].num_real_links = 1;
+ hb_objs[12].num_virtual_links = 0;
+ hb_objs[12].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[12].real_links[0].width = 2;
+ hb_objs[12].real_links[0].position = 0;
+ hb_objs[12].real_links[0].objidx = 12;
+ hb_objs[12].virtual_links = NULL;
+
+ hb_objs[13].head = &(test_gsub_data[10]);
+ hb_objs[13].tail = &(test_gsub_data[18]);
+ hb_objs[13].num_real_links = 1;
+ hb_objs[13].num_virtual_links = 0;
+ hb_objs[13].real_links = malloc (sizeof (hb_link_t));
+ hb_objs[13].real_links[0].width = 2;
+ hb_objs[13].real_links[0].position = 6;
+ hb_objs[13].real_links[0].objidx = 13;
+ hb_objs[13].virtual_links = NULL;
+
+ hb_objs[14].head = &(test_gsub_data[0]);
+ hb_objs[14].tail = &(test_gsub_data[10]);
+ hb_objs[14].num_real_links = 3;
+ hb_objs[14].num_virtual_links = 0;
+ hb_objs[14].real_links = calloc (3, sizeof (hb_link_t));
+ hb_objs[14].real_links[0].width = 2;
+ hb_objs[14].real_links[0].position = 8;
+ hb_objs[14].real_links[0].objidx = 9;
+ hb_objs[14].real_links[1].width = 2;
+ hb_objs[14].real_links[1].position = 6;
+ hb_objs[14].real_links[1].objidx = 11;
+ hb_objs[14].real_links[2].width = 2;
+ hb_objs[14].real_links[2].position = 4;
+ hb_objs[14].real_links[2].objidx = 14;
+ hb_objs[14].virtual_links = NULL;
+
+ hb_blob_t *result = hb_subset_repack_or_fail (HB_TAG_NONE, hb_objs, 15);
+
+ hb_face_t *face_expected = hb_test_open_font_file ("fonts/repacker_expected.otf");
+ hb_blob_t *expected_blob = hb_face_reference_table (face_expected, HB_TAG ('G','S','U','B'));
+ fprintf(stderr, "expected %d bytes, actual %d bytes\n", hb_blob_get_length(expected_blob), hb_blob_get_length (result));
+
+ if (hb_blob_get_length (expected_blob) != 0 ||
+ hb_blob_get_length (result) != 0)
+ hb_test_assert_blobs_equal (expected_blob, result);
+
+ hb_face_destroy (face_expected);
+ hb_blob_destroy (expected_blob);
+ hb_blob_destroy (result);
+
+ for (unsigned i = 0 ; i < 15; i++)
+ {
+ if (hb_objs[i].real_links != NULL)
+ free (hb_objs[i].real_links);
+ }
+
+ free (hb_objs);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_hb_repack_with_cy_struct);
+
+ return hb_test_run();
+}
+#else
+int main (int argc HB_UNUSED, char **argv HB_UNUSED)
+{
+ return 0;
+}
+#endif
diff --git a/test/api/test-subset.c b/test/api/test-subset.c
index 27bf73cc9..08c911076 100644
--- a/test/api/test-subset.c
+++ b/test/api/test-subset.c
@@ -155,6 +155,80 @@ test_subset_sets (void)
hb_subset_input_destroy (input);
}
+static void
+test_subset_plan (void)
+{
+ hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+ hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
+
+ hb_set_t *codepoints = hb_set_create();
+ hb_set_add (codepoints, 97);
+ hb_set_add (codepoints, 99);
+ hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+ hb_set_destroy (codepoints);
+
+ hb_subset_plan_t* plan = hb_subset_plan_create_or_fail (face_abc, input);
+ g_assert (plan);
+
+ const hb_map_t* mapping = hb_subset_plan_old_to_new_glyph_mapping (plan);
+ g_assert (hb_map_get (mapping, 1) == 1);
+ g_assert (hb_map_get (mapping, 3) == 2);
+
+ mapping = hb_subset_plan_new_to_old_glyph_mapping (plan);
+ g_assert (hb_map_get (mapping, 1) == 1);
+ g_assert (hb_map_get (mapping, 2) == 3);
+
+ mapping = hb_subset_plan_unicode_to_old_glyph_mapping (plan);
+ g_assert (hb_map_get (mapping, 0x63) == 3);
+
+ hb_face_t* face_abc_subset = hb_subset_plan_execute_or_fail (plan);
+
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+
+ hb_subset_input_destroy (input);
+ hb_subset_plan_destroy (plan);
+ hb_face_destroy (face_abc_subset);
+ hb_face_destroy (face_abc);
+ hb_face_destroy (face_ac);
+}
+
+static hb_blob_t*
+_ref_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+{
+ return hb_face_reference_table ((hb_face_t*) user_data, tag);
+}
+
+static void
+test_subset_create_for_tables_face (void)
+{
+ hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+ hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
+ hb_face_t *face_create_for_tables = hb_face_create_for_tables (
+ _ref_table,
+ face_abc,
+ NULL);
+
+ hb_set_t *codepoints = hb_set_create();
+ hb_set_add (codepoints, 97);
+ hb_set_add (codepoints, 99);
+
+ hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+ hb_set_destroy (codepoints);
+
+ hb_face_t* face_abc_subset = hb_subset_or_fail (face_create_for_tables, input);
+
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','a','s','p'));
+
+ hb_subset_input_destroy (input);
+ hb_face_destroy (face_abc_subset);
+ hb_face_destroy (face_create_for_tables);
+ hb_face_destroy (face_abc);
+ hb_face_destroy (face_ac);
+}
+
int
main (int argc, char **argv)
{
@@ -165,6 +239,8 @@ main (int argc, char **argv)
hb_test_add (test_subset_crash);
hb_test_add (test_subset_set_flags);
hb_test_add (test_subset_sets);
+ hb_test_add (test_subset_plan);
+ hb_test_add (test_subset_create_for_tables_face);
return hb_test_run();
}
diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c
index dd1e3d06c..857308b33 100644
--- a/test/api/test-unicode.c
+++ b/test/api/test-unicode.c
@@ -184,6 +184,9 @@ static const test_pair_t combining_class_tests_more[] =
/* Unicode-14.0 character additions */
{ 0x1DFA, 218 },
+ /* Unicode-15.0 character additions */
+ { 0x10EFD, 220 },
+
{ 0x111111, 0 }
};
@@ -267,6 +270,9 @@ static const test_pair_t general_category_tests_more[] =
/* Unicode-14.0 character additions */
{ 0x20C0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
+ /* Unicode-15.0 character additions */
+ { 0x0CF3, HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK },
+
{ 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
};
@@ -524,6 +530,10 @@ static const test_pair_t script_tests_more[] =
{ 0x16A70, HB_SCRIPT_TANGSA },
{ 0x1E290, HB_SCRIPT_TOTO },
+ /* Unicode-15.0 additions */
+ { 0x11F00, HB_SCRIPT_KAWI },
+ { 0x1E4D0, HB_SCRIPT_NAG_MUNDARI },
+
{ 0x111111, HB_SCRIPT_UNKNOWN }
};
@@ -744,9 +754,9 @@ test_unicode_setters (void)
/* Since uf is immutable now, the following setter should do nothing. */
p->func_setter (uf, (get_func_t) a_is_for_arabic_get_script, &data[1], free_up);
- g_assert (data[0].freed && !data[1].freed);
+ g_assert (data[0].freed && data[1].freed);
hb_unicode_funcs_destroy (uf);
- g_assert (data[0].freed && !data[1].freed);
+ g_assert (data[0].freed && data[1].freed);
}
}
diff --git a/test/api/test-var-coords.c b/test/api/test-var-coords.c
index aa152e3ed..490e5fc06 100644
--- a/test/api/test-var-coords.c
+++ b/test/api/test-var-coords.c
@@ -31,7 +31,6 @@
static void
test_get_var_coords (void)
{
-#ifdef HB_EXPERIMENTAL_API
#ifndef G_APPROX_VALUE
#define G_APPROX_VALUE(a, b, epsilon) \
(((a) > (b) ? (a) - (b) : (b) - (a)) < (epsilon))
@@ -66,7 +65,6 @@ test_get_var_coords (void)
hb_font_destroy (font);
hb_face_destroy (face);
-#endif
}
static void
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index 2e2b2c9ad..27ffae6fe 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -16,7 +16,7 @@ $(top_builddir)/src/libharfbuzz.la: lib
$(top_builddir)/src/libharfbuzz-subset.la: libs
EXTRA_DIST += \
- README \
+ README.md \
run-shape-fuzzer-tests.py \
run-subset-fuzzer-tests.py \
run-draw-fuzzer-tests.py \
diff --git a/test/fuzzing/README b/test/fuzzing/README
deleted file mode 100644
index af99cf95a..000000000
--- a/test/fuzzing/README
+++ /dev/null
@@ -1,21 +0,0 @@
-In order to build the fuzzer one needs to build HarfBuzz and
-harfbuzz/test/fuzzing/hb-fuzzer.cc with:
- - Using the most recent Clang
- - With -fsanitize=address (or =undefined, or a combination)
- - With -fsanitize-coverage=edge[,8bit-counters,trace-cmp]
- - With various defines that limit worst case exponential behavior.
- See FUZZING_CPPFLAGS in harfbuzz/src/Makefile.am for the list.
- - link against libFuzzer
-
-To run the fuzzer one needs to first obtain a test corpus as a directory
-containing interesting fonts. A good starting point is inside
-harfbuzz/test/shaping/fonts/fonts/.
-Then, run the fuzzer like this:
- ./hb-fuzzer -max_len=2048 CORPUS_DIR
-Where max_len specifies the maximal length of font files to handle.
-The smaller the faster.
-
-For more details consult the following locations:
- - http://llvm.org/docs/LibFuzzer.html or
- - https://github.com/google/libfuzzer-bot/tree/master/harfbuzz
- - https://github.com/harfbuzz/harfbuzz/issues/139
diff --git a/test/fuzzing/README.md b/test/fuzzing/README.md
new file mode 100644
index 000000000..8529a0c65
--- /dev/null
+++ b/test/fuzzing/README.md
@@ -0,0 +1,17 @@
+To build the fuzzers with libFuzzer to perform actual fuzzing, build with:
+
+```shell
+CXX=clang++ CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer"
+
+ninja -Cfuzzbuild
+```
+
+Then, run the fuzzer like this:
+
+fuzzbuild/test/fuzzing/hb-{shape,draw,subset,set}-fuzzer [-max_len=2048] [CORPUS_DIR]
+
+Where max_len specifies the maximal length of font files to handle.
+The smaller the faster.
+
+For more details consult the following locations:
+ - http://llvm.org/docs/LibFuzzer.html
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152
new file mode 100644
index 000000000..98c2fb7d0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464
new file mode 100644
index 000000000..140481059
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584
new file mode 100644
index 000000000..9adb77914
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-4856957815619584
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040
new file mode 100644
index 000000000..179122557
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800
new file mode 100644
index 000000000..d66fb2af5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512
new file mode 100644
index 000000000..7c71adaa6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040
new file mode 100644
index 000000000..333ebaa0a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664
new file mode 100644
index 000000000..4b2f3cb2f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4979711393005568 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4979711393005568
new file mode 100644
index 000000000..1d32c3b17
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4979711393005568
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760
new file mode 100644
index 000000000..81bd99161
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5205038086094848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5205038086094848
new file mode 100644
index 000000000..db845043f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5205038086094848
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192
new file mode 100644
index 000000000..8cd77eacd
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248
new file mode 100644
index 000000000..f5f3cff75
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5422577634377728 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5422577634377728
new file mode 100644
index 000000000..aba40f13a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5422577634377728
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5549945449480192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5549945449480192
new file mode 100644
index 000000000..62072f177
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5549945449480192
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296
new file mode 100644
index 000000000..b2038a601
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672
new file mode 100644
index 000000000..19521a101
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608
new file mode 100644
index 000000000..faf2e8577
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648
new file mode 100644
index 000000000..3a15ab230
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216
new file mode 100644
index 000000000..c5bd724d2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416
new file mode 100644
index 000000000..6da6a1c99
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416
Binary files differ
diff --git a/test/fuzzing/fonts/crash-d223bc42a8226c4d655c417d63d9a76760d05985 b/test/fuzzing/fonts/crash-d223bc42a8226c4d655c417d63d9a76760d05985
new file mode 100644
index 000000000..8795db1a2
--- /dev/null
+++ b/test/fuzzing/fonts/crash-d223bc42a8226c4d655c417d63d9a76760d05985
Binary files differ
diff --git a/test/fuzzing/fonts/sbix-extents.ttf b/test/fuzzing/fonts/sbix-extents.ttf
new file mode 100644
index 000000000..6f792df70
--- /dev/null
+++ b/test/fuzzing/fonts/sbix-extents.ttf
Binary files differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448
new file mode 100644
index 000000000..54ee81658
--- /dev/null
+++ b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448
Binary files differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344
new file mode 100644
index 000000000..a29d1e2fb
--- /dev/null
+++ b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344
Binary files differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728
new file mode 100644
index 000000000..aeee90b6c
--- /dev/null
+++ b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728
Binary files differ
diff --git a/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4 b/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4
new file mode 100644
index 000000000..ff8da7b29
--- /dev/null
+++ b/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4
Binary files differ
diff --git a/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774 b/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774
new file mode 100644
index 000000000..0160ce59b
--- /dev/null
+++ b/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774
Binary files differ
diff --git a/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527 b/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527
new file mode 100644
index 000000000..58b4075ad
--- /dev/null
+++ b/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527
Binary files differ
diff --git a/test/fuzzing/graphs/noto_nastaliq_urdu b/test/fuzzing/graphs/noto_nastaliq_urdu
new file mode 100644
index 000000000..2e3cab886
--- /dev/null
+++ b/test/fuzzing/graphs/noto_nastaliq_urdu
Binary files differ
diff --git a/test/fuzzing/hb-draw-fuzzer.cc b/test/fuzzing/hb-draw-fuzzer.cc
index 772a35831..5c53eb271 100644
--- a/test/fuzzing/hb-draw-fuzzer.cc
+++ b/test/fuzzing/hb-draw-fuzzer.cc
@@ -5,77 +5,81 @@
#include "hb-fuzzer.hh"
-#ifdef HB_EXPERIMENTAL_API
-struct _user_data_t
+struct _draw_data_t
{
- bool is_open;
unsigned path_len;
- hb_position_t path_start_x;
- hb_position_t path_start_y;
- hb_position_t path_last_x;
- hb_position_t path_last_y;
+ float path_start_x;
+ float path_start_y;
+ float path_last_x;
+ float path_last_y;
};
+#include <cstdio>
static void
-_move_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_move_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data)
{
- _user_data_t *user_data = (_user_data_t *) user_data_;
- assert (!user_data->is_open);
- user_data->is_open = true;
- user_data->path_start_x = user_data->path_last_x = to_x;
- user_data->path_start_y = user_data->path_last_y = to_y;
+ _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+ assert (!st->path_open);
+ draw_data->path_start_x = draw_data->path_last_x = to_x;
+ draw_data->path_start_y = draw_data->path_last_y = to_y;
}
static void
-_line_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_line_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *user_data)
{
- _user_data_t *user_data = (_user_data_t *) user_data_;
- assert (user_data->is_open);
- assert (user_data->path_last_x != to_x || user_data->path_last_y != to_y);
- ++user_data->path_len;
- user_data->path_last_x = to_x;
- user_data->path_last_y = to_y;
+ _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+ assert (st->path_open);
+ ++draw_data->path_len;
+ draw_data->path_last_x = to_x;
+ draw_data->path_last_y = to_y;
}
static void
-_quadratic_to (hb_position_t control_x, hb_position_t control_y,
- hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+ hb_draw_state_t *st,
+ float control_x, float control_y,
+ float to_x, float to_y,
+ void *user_data)
{
- _user_data_t *user_data = (_user_data_t *) user_data_;
- assert (user_data->is_open);
- assert (user_data->path_last_x != control_x || user_data->path_last_y != control_y ||
- user_data->path_last_x != to_x || user_data->path_last_y != to_y);
- ++user_data->path_len;
- user_data->path_last_x = to_x;
- user_data->path_last_y = to_y;
+ _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+ assert (st->path_open);
+ ++draw_data->path_len;
+ draw_data->path_last_x = to_x;
+ draw_data->path_last_y = to_y;
}
static void
-_cubic_to (hb_position_t control1_x, hb_position_t control1_y,
- hb_position_t control2_x, hb_position_t control2_y,
- hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *user_data)
{
- _user_data_t *user_data = (_user_data_t *) user_data_;
- assert (user_data->is_open);
- assert (user_data->path_last_x != control1_x || user_data->path_last_y != control1_y ||
- user_data->path_last_x != control2_x || user_data->path_last_y != control2_y ||
- user_data->path_last_x != to_x || user_data->path_last_y != to_y);
- ++user_data->path_len;
- user_data->path_last_x = to_x;
- user_data->path_last_y = to_y;
+ _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+ assert (st->path_open);
+ ++draw_data->path_len;
+ draw_data->path_last_x = to_x;
+ draw_data->path_last_y = to_y;
}
static void
-_close_path (void *user_data_)
+_close_path (hb_draw_funcs_t *dfuncs, void *draw_data_,
+ hb_draw_state_t *st,
+ void *user_data)
{
- _user_data_t *user_data = (_user_data_t *) user_data_;
- assert (user_data->is_open && user_data->path_len != 0);
- user_data->path_len = 0;
- user_data->is_open = false;
- assert (user_data->path_start_x == user_data->path_last_x &&
- user_data->path_start_y == user_data->path_last_y);
+ _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+ assert (st->path_open && draw_data->path_len != 0);
+ draw_data->path_len = 0;
+ assert (draw_data->path_start_x == draw_data->path_last_x &&
+ draw_data->path_start_y == draw_data->path_last_y);
}
-#endif
/* Similar to test-ot-face.c's #test_font() */
static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set, hb_codepoint_t cp)
@@ -115,7 +119,7 @@ static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set,
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
{
- alloc_state = size; /* see src/failing-alloc.c */
+ alloc_state = _fuzzing_alloc_state (data, size);
hb_blob_t *blob = hb_blob_create ((const char *) data, size,
HB_MEMORY_MODE_READONLY, nullptr, nullptr);
@@ -135,24 +139,19 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
unsigned glyph_count = hb_face_get_glyph_count (face);
glyph_count = glyph_count > 16 ? 16 : glyph_count;
-#ifdef HB_EXPERIMENTAL_API
- _user_data_t user_data = {false, 0, 0, 0, 0, 0};
+ _draw_data_t draw_data = {0, 0, 0, 0, 0};
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to);
- hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to);
- hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to);
- hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to);
- hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path);
-#endif
+ hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to, nullptr, nullptr);
+ hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to, nullptr, nullptr);
+ hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to, nullptr, nullptr);
+ hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to, nullptr, nullptr);
+ hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path, nullptr, nullptr);
volatile unsigned counter = !glyph_count;
hb_set_t *set = hb_set_create ();
for (unsigned gid = 0; gid < glyph_count; ++gid)
{
-#ifdef HB_EXPERIMENTAL_API
- hb_font_draw_glyph (font, gid, funcs, &user_data);
- assert (!user_data.is_open);
-#endif
+ hb_font_get_glyph_shape (font, gid, funcs, &draw_data);
/* Glyph extents also may practices the similar path, call it now that is related */
hb_glyph_extents_t extents;
@@ -166,9 +165,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
}
hb_set_destroy (set);
assert (counter);
-#ifdef HB_EXPERIMENTAL_API
hb_draw_funcs_destroy (funcs);
-#endif
hb_font_destroy (font);
hb_face_destroy (face);
diff --git a/test/fuzzing/hb-fuzzer.hh b/test/fuzzing/hb-fuzzer.hh
index 52e00dd0e..b7090a94a 100644
--- a/test/fuzzing/hb-fuzzer.hh
+++ b/test/fuzzing/hb-fuzzer.hh
@@ -10,9 +10,25 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size);
#endif
#ifdef HB_IS_IN_FUZZER
+
/* See src/failing-alloc.c */
extern "C" int alloc_state;
+
#else
+
/* Just a dummy global variable */
static int HB_UNUSED alloc_state = 0;
+
#endif
+
+static inline int
+_fuzzing_alloc_state (const uint8_t *data, size_t size)
+{
+ /* https://github.com/harfbuzz/harfbuzz/pull/2764#issuecomment-1172589849 */
+
+ /* In 50% of the runs, don't fail the allocator. */
+ if (size && data[size - 1] < 0x80)
+ return 0;
+
+ return size;
+}
diff --git a/test/fuzzing/hb-repacker-fuzzer.cc b/test/fuzzing/hb-repacker-fuzzer.cc
new file mode 100644
index 000000000..0b06fd2af
--- /dev/null
+++ b/test/fuzzing/hb-repacker-fuzzer.cc
@@ -0,0 +1,145 @@
+#include "hb-fuzzer.hh"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hb-subset-repacker.h"
+
+typedef struct
+{
+ uint16_t parent;
+ uint16_t child;
+ uint16_t position;
+ uint8_t width;
+} link_t;
+
+/* The fuzzer seed contains a serialized representation of a object graph which forms
+ * the input graph to the repacker call. The binary format is:
+ *
+ * table tag: 4 bytes
+ * number of objects: 2 bytes
+ * objects[number of objects]:
+ * blob size: 2 bytes
+ * blob: blob size bytes
+ * num of real links: 2 bytes
+ * links[number of real links]: link_t struct
+ *
+ * TODO(garretrieger): add optional virtual links
+ */
+
+template <typename T>
+bool read(const uint8_t** data, size_t* size, T* out)
+{
+ if (*size < sizeof (T)) return false;
+
+ memcpy(out, *data, sizeof (T));
+
+ *data += sizeof (T);
+ *size -= sizeof (T);
+
+ return true;
+}
+
+void cleanup (hb_object_t* objects, uint16_t num_objects)
+{
+ for (uint32_t i = 0; i < num_objects; i++)
+ {
+ free (objects[i].head);
+ free (objects[i].real_links);
+ }
+}
+
+void add_links_to_objects (hb_object_t* objects, uint16_t num_objects,
+ link_t* links, uint16_t num_links)
+{
+ unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned));
+
+ for (uint32_t i = 0; i < num_links; i++)
+ {
+ uint16_t parent_idx = links[i].parent;
+ link_count[parent_idx]++;
+ }
+
+ for (uint32_t i = 0; i < num_objects; i++)
+ {
+ objects[i].num_real_links = link_count[i];
+ objects[i].real_links = (hb_link_t*) calloc (link_count[i], sizeof (hb_link_t));
+ objects[i].num_virtual_links = 0;
+ objects[i].virtual_links = nullptr;
+ }
+
+ for (uint32_t i = 0; i < num_links; i++)
+ {
+ uint16_t parent_idx = links[i].parent;
+ uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object.
+ hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]);
+
+ link->width = links[i].width;
+ link->position = links[i].position;
+ link->objidx = child_idx;
+ link_count[parent_idx]--;
+ }
+
+ free (link_count);
+}
+
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
+{
+ // TODO(garretrieger): move graph validity checks into repacker graph creation.
+ alloc_state = _fuzzing_alloc_state (data, size);
+
+ uint16_t num_objects = 0;
+ hb_object_t* objects = nullptr;
+
+ uint16_t num_real_links = 0;
+ link_t* links = nullptr;
+
+ hb_tag_t table_tag;
+ if (!read<hb_tag_t> (&data, &size, &table_tag)) goto end;
+ if (!read<uint16_t> (&data, &size, &num_objects)) goto end;
+
+ objects = (hb_object_t*) calloc (num_objects, sizeof (hb_object_t));
+ for (uint32_t i = 0; i < num_objects; i++)
+ {
+ uint16_t blob_size;
+ if (!read<uint16_t> (&data, &size, &blob_size)) goto end;
+ if (size < blob_size) goto end;
+
+ char* copy = (char*) calloc (1, blob_size);
+ memcpy (copy, data, blob_size);
+ objects[i].head = (char*) copy;
+ objects[i].tail = (char*) (copy + blob_size);
+
+ size -= blob_size;
+ data += blob_size;
+ }
+
+ if (!read<uint16_t> (&data, &size, &num_real_links)) goto end;
+ links = (link_t*) calloc (num_real_links, sizeof (link_t));
+ for (uint32_t i = 0; i < num_real_links; i++)
+ {
+ if (!read<link_t> (&data, &size, &links[i])) goto end;
+
+ if (links[i].parent >= num_objects)
+ goto end;
+ }
+
+ add_links_to_objects (objects, num_objects,
+ links, num_real_links);
+
+ hb_blob_destroy (hb_subset_repack_or_fail (table_tag,
+ objects,
+ num_objects));
+
+end:
+ if (objects)
+ {
+ cleanup (objects, num_objects);
+ free (objects);
+ }
+ free (links);
+
+ return 0;
+}
diff --git a/test/fuzzing/hb-set-fuzzer.cc b/test/fuzzing/hb-set-fuzzer.cc
index 0a547f3a0..065e54902 100644
--- a/test/fuzzing/hb-set-fuzzer.cc
+++ b/test/fuzzing/hb-set-fuzzer.cc
@@ -8,7 +8,7 @@
#include "hb.h"
// Only allow ~5,000 set values between the two input sets.
-// Arbitarily long input sets do not trigger any meaningful
+// Arbitrarily long input sets do not trigger any meaningful
// differences in behaviour so there's no benefit from allowing
// the fuzzer to create super large sets.
#define MAX_INPUT_SIZE 20000
@@ -38,7 +38,7 @@ static hb_set_t *create_set (const uint32_t *value_array, int count)
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
{
- alloc_state = size; /* see src/failing-alloc.c */
+ alloc_state = _fuzzing_alloc_state (data, size);
if (size < sizeof (instructions_t))
return 0;
diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc
index 661ea9ffa..f14f6518e 100644
--- a/test/fuzzing/hb-shape-fuzzer.cc
+++ b/test/fuzzing/hb-shape-fuzzer.cc
@@ -11,7 +11,7 @@
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
{
- alloc_state = size; /* see src/failing-alloc.c */
+ alloc_state = _fuzzing_alloc_state (data, size);
hb_blob_t *blob = hb_blob_create ((const char *)data, size,
HB_MEMORY_MODE_READONLY, nullptr, nullptr);
@@ -33,6 +33,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
{
const char text[] = "ABCDEXYZ123@_%&)*$!";
hb_buffer_t *buffer = hb_buffer_create ();
+ hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_VERIFY /* | HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT */));
hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
hb_buffer_guess_segment_properties (buffer);
hb_shape (font, buffer, nullptr, 0);
@@ -50,6 +51,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
text32[10] = test_font (font, text32[15]) % 256;
hb_buffer_t *buffer = hb_buffer_create ();
+ // hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_VERIFY | HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT));
hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
hb_buffer_guess_segment_properties (buffer);
hb_shape (font, buffer, nullptr, 0);
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index fa95c8735..f883a3d3c 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -45,7 +45,7 @@ trySubset (hb_face_t *face,
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
{
- alloc_state = size; /* see src/failing-alloc.c */
+ alloc_state = _fuzzing_alloc_state (data, size);
hb_blob_t *blob = hb_blob_create ((const char *) data, size,
HB_MEMORY_MODE_READONLY, nullptr, nullptr);
diff --git a/test/fuzzing/meson.build b/test/fuzzing/meson.build
index 9ddb4b2c7..d38ca8f9f 100644
--- a/test/fuzzing/meson.build
+++ b/test/fuzzing/meson.build
@@ -5,6 +5,10 @@ tests = [
'hb-draw-fuzzer.cc',
]
+if get_option('experimental_api')
+ tests += 'hb-repacker-fuzzer.cc'
+endif
+
foreach file_name : tests
test_name = file_name.split('.')[0]
@@ -19,6 +23,10 @@ foreach file_name : tests
extra_cpp_args += '-DHB_IS_IN_FUZZER'
endif
+ if get_option('experimental_api')
+ extra_cpp_args += '-DHB_EXPERIMENTAL_API'
+ endif
+
exe = executable(test_name, sources,
cpp_args: cpp_args + extra_cpp_args,
include_directories: [incconfig, incsrc],
@@ -38,7 +46,7 @@ test('shape_fuzzer', find_program('run-shape-fuzzer-tests.py'),
],
timeout: 300,
depends: [hb_shape_fuzzer_exe, libharfbuzz, libharfbuzz_subset],
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
+ workdir: meson.current_build_dir() / '..' / '..',
env: env,
suite: ['fuzzing', 'slow'],
)
@@ -50,16 +58,30 @@ test('subset_fuzzer', find_program('run-subset-fuzzer-tests.py'),
# as the tests are ran concurrently let's raise acceptable time here
# ideally better to break and let meson handles them in parallel
timeout: 300,
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
+ workdir: meson.current_build_dir() / '..' / '..',
env: env,
suite: ['fuzzing', 'slow'],
)
+if get_option('experimental_api')
+ test('repacker_fuzzer', find_program('run-repacker-fuzzer-tests.py'),
+ args: [
+ hb_repacker_fuzzer_exe,
+ ],
+ # as the tests are ran concurrently let's raise acceptable time here
+ # ideally better to break and let meson handles them in parallel
+ timeout: 300,
+ workdir: meson.current_build_dir() / '..' / '..',
+ env: env,
+ suite: ['fuzzing', 'slow'],
+ )
+endif
+
test('draw_fuzzer', find_program('run-draw-fuzzer-tests.py'),
args: [
hb_draw_fuzzer_exe,
],
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
+ workdir: meson.current_build_dir() / '..' / '..',
env: env,
suite: ['fuzzing'],
)
diff --git a/test/fuzzing/run-repacker-fuzzer-tests.py b/test/fuzzing/run-repacker-fuzzer-tests.py
new file mode 100644
index 000000000..85a23e13e
--- /dev/null
+++ b/test/fuzzing/run-repacker-fuzzer-tests.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+
+import sys, os, subprocess, tempfile, shutil
+
+
+def cmd (command):
+ # https://stackoverflow.com/a/4408409 as we might have huge output sometimes
+ with tempfile.TemporaryFile () as tempf:
+ p = subprocess.Popen (command, stderr=tempf)
+
+ try:
+ p.wait ()
+ tempf.seek (0)
+ text = tempf.read ()
+
+ #TODO: Detect debug mode with a better way
+ is_debug_mode = b"SANITIZE" in text
+
+ return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode
+ except subprocess.TimeoutExpired:
+ return 'error: timeout, ' + ' '.join (command), 1
+
+
+srcdir = os.getenv ("srcdir", ".")
+EXEEXT = os.getenv ("EXEEXT", "")
+top_builddir = os.getenv ("top_builddir", ".")
+hb_repacker_fuzzer = os.path.join (top_builddir, "hb-repacker-fuzzer" + EXEEXT)
+
+if not os.path.exists (hb_repacker_fuzzer):
+ if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]):
+ sys.exit ("""Failed to find hb-repacker-fuzzer binary automatically,
+please provide it as the first argument to the tool""")
+
+ hb_repacker_fuzzer = sys.argv[1]
+
+print ('hb_repacker_fuzzer:', hb_repacker_fuzzer)
+fails = 0
+
+valgrind = None
+if os.getenv ('RUN_VALGRIND', ''):
+ valgrind = shutil.which ('valgrind')
+ if valgrind is None:
+ sys.exit ("""Valgrind requested but not found.""")
+
+def run_dir (parent_path):
+ global fails
+ for file in os.listdir (parent_path):
+ path = os.path.join(parent_path, file)
+ print ("running repacker fuzzer against %s" % path)
+ if valgrind:
+ text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_repacker_fuzzer, path])
+ else:
+ text, returncode = cmd ([hb_repacker_fuzzer, path])
+ if 'error' in text:
+ returncode = 1
+
+ if (not valgrind or returncode) and text.strip ():
+ print (text)
+
+ if returncode != 0:
+ print ("failed for %s" % path)
+ fails = fails + 1
+
+
+run_dir (os.path.join (srcdir, "graphs"))
+
+if fails:
+ sys.exit ("%d repacker fuzzer related tests failed." % fails)
diff --git a/test/meson.build b/test/meson.build
index 8b4b83f78..371b7ef8a 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -2,3 +2,4 @@ subdir('api')
subdir('shape')
subdir('subset')
subdir('fuzzing')
+subdir('threads')
diff --git a/test/shape/Makefile.am b/test/shape/Makefile.am
index 316b173c8..bb4d91966 100644
--- a/test/shape/Makefile.am
+++ b/test/shape/Makefile.am
@@ -25,7 +25,6 @@ EXTRA_DIST += \
hb-unicode-prettyname \
record-test.sh \
run-tests.py \
- texts/in-house \
$(NULL)
# TODO Figure out Python stuff
diff --git a/test/shape/README.md b/test/shape/README.md
index f386fb965..08cdcdc7b 100644
--- a/test/shape/README.md
+++ b/test/shape/README.md
@@ -14,7 +14,7 @@ FontTools from <https://github.com/behdad/fonttools>.
To use `record-test.sh`, just put it right before the `hb-shape` invocation:
```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-shape font.ttf
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-subset ../../util/hb-shape font.ttf
```
what this does is:
* Subset the font for the sequence of Unicode characters requested,
@@ -28,7 +28,7 @@ what this does is:
to an existing or new test file in `data/in-house/tests` using `-o`,
e.g.:
```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o data/in-house/tests/test-name.test ../../util/hb-shape font.ttf
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o data/in-house/tests/test-name.tests ../../util/hb-subset ../../util/hb-shape font.ttf
```
If you created a new test file, add it to `data/in-house/Makefile.sources`
diff --git a/test/shape/data/aots/Makefile.sources b/test/shape/data/aots/Makefile.sources
index ffa311b15..fcbea611c 100644
--- a/test/shape/data/aots/Makefile.sources
+++ b/test/shape/data/aots/Makefile.sources
@@ -128,6 +128,3 @@ TESTS = \
tests/lookupflag_ignore_ligatures.tests \
tests/lookupflag_ignore_marks.tests \
$(NULL)
-
-DISABLED_TESTS = \
- $(NULL)
diff --git a/test/shape/data/aots/hb-aots-tester.cpp b/test/shape/data/aots/hb-aots-tester.cpp
index 152858410..51958fc55 100644
--- a/test/shape/data/aots/hb-aots-tester.cpp
+++ b/test/shape/data/aots/hb-aots-tester.cpp
@@ -179,7 +179,7 @@ bool gsub_test(const char *testName,
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
- fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions;");
+ fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --no-positions;");
for (unsigned int i = 0; i < nbIn; i++)
{
@@ -258,7 +258,7 @@ bool cmap_test(const char *testName,
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
- fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;");
+ fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;");
for (unsigned int i = 0; i < nbIn; i++)
{
@@ -388,7 +388,7 @@ bool gpos_test(const char *testName,
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
- fprintf (tests_file, "\" --no-clusters --no-glyph-names --ned;");
+ fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --ned;");
for (unsigned int i = 0; i < nbIn; i++)
{
diff --git a/test/shape/data/aots/tests/classdef1.tests b/test/shape/data/aots/tests/classdef1.tests
index b19f358c0..00b41b92e 100644
--- a/test/shape/data/aots/tests/classdef1.tests
+++ b/test/shape/data/aots/tests/classdef1.tests
@@ -1 +1 @@
-../fonts/classdef1_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
+../fonts/classdef1_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
diff --git a/test/shape/data/aots/tests/classdef1_empty.tests b/test/shape/data/aots/tests/classdef1_empty.tests
index 28d02373c..3167411fb 100644
--- a/test/shape/data/aots/tests/classdef1_empty.tests
+++ b/test/shape/data/aots/tests/classdef1_empty.tests
@@ -1 +1 @@
-../fonts/classdef1_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
+../fonts/classdef1_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef1_multiple.tests b/test/shape/data/aots/tests/classdef1_multiple.tests
index b5bebc496..3bbe70495 100644
--- a/test/shape/data/aots/tests/classdef1_multiple.tests
+++ b/test/shape/data/aots/tests/classdef1_multiple.tests
@@ -1 +1 @@
-../fonts/classdef1_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
+../fonts/classdef1_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shape/data/aots/tests/classdef1_single.tests b/test/shape/data/aots/tests/classdef1_single.tests
index 0390af52b..d15673c16 100644
--- a/test/shape/data/aots/tests/classdef1_single.tests
+++ b/test/shape/data/aots/tests/classdef1_single.tests
@@ -1 +1 @@
-../fonts/classdef2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
+../fonts/classdef2_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef2.tests b/test/shape/data/aots/tests/classdef2.tests
index bf22d4ebe..4fec83921 100644
--- a/test/shape/data/aots/tests/classdef2.tests
+++ b/test/shape/data/aots/tests/classdef2.tests
@@ -1 +1 @@
-../fonts/classdef2_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
+../fonts/classdef2_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
diff --git a/test/shape/data/aots/tests/classdef2_empty.tests b/test/shape/data/aots/tests/classdef2_empty.tests
index 652dc116c..717636adf 100644
--- a/test/shape/data/aots/tests/classdef2_empty.tests
+++ b/test/shape/data/aots/tests/classdef2_empty.tests
@@ -1 +1 @@
-../fonts/classdef2_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
+../fonts/classdef2_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef2_multiple.tests b/test/shape/data/aots/tests/classdef2_multiple.tests
index 25af349b3..a69d61318 100644
--- a/test/shape/data/aots/tests/classdef2_multiple.tests
+++ b/test/shape/data/aots/tests/classdef2_multiple.tests
@@ -1 +1 @@
-../fonts/classdef2_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
+../fonts/classdef2_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shape/data/aots/tests/classdef2_single.tests b/test/shape/data/aots/tests/classdef2_single.tests
index 0390af52b..d15673c16 100644
--- a/test/shape/data/aots/tests/classdef2_single.tests
+++ b/test/shape/data/aots/tests/classdef2_single.tests
@@ -1 +1 @@
-../fonts/classdef2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
+../fonts/classdef2_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/cmap0.tests b/test/shape/data/aots/tests/cmap0.tests
index 200527eca..83ae1d791 100644
--- a/test/shape/data/aots/tests/cmap0.tests
+++ b/test/shape/data/aots/tests/cmap0.tests
@@ -1 +1 @@
-../fonts/cmap0_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+FFFF;[0|0|0|17|56|12|0|0]
+../fonts/cmap0_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+FFFF;[0|0|0|17|56|12|0|0]
diff --git a/test/shape/data/aots/tests/cmap10.tests b/test/shape/data/aots/tests/cmap10.tests
index 4d2038485..9388c057c 100644
--- a/test/shape/data/aots/tests/cmap10.tests
+++ b/test/shape/data/aots/tests/cmap10.tests
@@ -1,2 +1,2 @@
-../fonts/cmap10_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|0|26|27|32|0]
-../fonts/cmap10_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
+../fonts/cmap10_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|0|26|27|32|0]
+../fonts/cmap10_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
diff --git a/test/shape/data/aots/tests/cmap12.tests b/test/shape/data/aots/tests/cmap12.tests
index 9354a68f8..9d9cf14f4 100644
--- a/test/shape/data/aots/tests/cmap12.tests
+++ b/test/shape/data/aots/tests/cmap12.tests
@@ -1 +1 @@
-../fonts/cmap12_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+101723,U+101724,U+101727,U+101728,U+102522,U+102523,U+102527,U+102528,U+FFFF;[0|0|0|23|24|27|0|0|53|57|0|0]
+../fonts/cmap12_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+101723,U+101724,U+101727,U+101728,U+102522,U+102523,U+102527,U+102528,U+FFFF;[0|0|0|23|24|27|0|0|53|57|0|0]
diff --git a/test/shape/data/aots/tests/cmap2.tests b/test/shape/data/aots/tests/cmap2.tests
index d8a992fb4..2ffc35170 100644
--- a/test/shape/data/aots/tests/cmap2.tests
+++ b/test/shape/data/aots/tests/cmap2.tests
@@ -1 +1 @@
-#../fonts/cmap2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0]
+#../fonts/cmap2_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0]
diff --git a/test/shape/data/aots/tests/cmap4.tests b/test/shape/data/aots/tests/cmap4.tests
index a0d17ab92..2416afc94 100644
--- a/test/shape/data/aots/tests/cmap4.tests
+++ b/test/shape/data/aots/tests/cmap4.tests
@@ -1,6 +1,6 @@
-../fonts/cmap4_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|40|41|53|0|0|256|261|266|0|0]
-../fonts/cmap4_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|0]
-../fonts/cmap4_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|65534]
-../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+AFC7,U+AFC8,U+AFC9,U+B02B,U+B02C,U+B02D;[0|0|44500|44501|44599|44600|0]
-#../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+FDE7,U+FDE8,U+FDE9,U+FE0B,U+FE0C,U+FE0D,U+FE4C,U+FE4D;[0|0|65500|65501|65535|0]
-../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0063,U+0064,U+01F3,U+01F4,U+01F5,U+03E8,U+03E9;[0|0|65136|65535|0|1|500|0]
+../fonts/cmap4_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|40|41|53|0|0|256|261|266|0|0]
+../fonts/cmap4_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|0]
+../fonts/cmap4_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|65534]
+../fonts/cmap4_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+AFC7,U+AFC8,U+AFC9,U+B02B,U+B02C,U+B02D;[0|0|44500|44501|44599|44600|0]
+#../fonts/cmap4_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+FDE7,U+FDE8,U+FDE9,U+FE0B,U+FE0C,U+FE0D,U+FE4C,U+FE4D;[0|0|65500|65501|65535|0]
+../fonts/cmap4_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0063,U+0064,U+01F3,U+01F4,U+01F5,U+03E8,U+03E9;[0|0|65136|65535|0|1|500|0]
diff --git a/test/shape/data/aots/tests/cmap6.tests b/test/shape/data/aots/tests/cmap6.tests
index bb5af86d0..c79d4d859 100644
--- a/test/shape/data/aots/tests/cmap6.tests
+++ b/test/shape/data/aots/tests/cmap6.tests
@@ -1,2 +1,2 @@
-../fonts/cmap6_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|17|56|12|0|0]
-../fonts/cmap6_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
+../fonts/cmap6_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|17|56|12|0|0]
+../fonts/cmap6_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
diff --git a/test/shape/data/aots/tests/cmap8.tests b/test/shape/data/aots/tests/cmap8.tests
index f65e01500..62cd94142 100644
--- a/test/shape/data/aots/tests/cmap8.tests
+++ b/test/shape/data/aots/tests/cmap8.tests
@@ -1 +1 @@
-#../fonts/cmap8_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0|26|27|32|0]
+#../fonts/cmap8_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0|26|27|32|0]
diff --git a/test/shape/data/aots/tests/gpos1_1_lookupflag.tests b/test/shape/data/aots/tests/gpos1_1_lookupflag.tests
index d59ed6281..790d9df07 100644
--- a/test/shape/data/aots/tests/gpos1_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos1_1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gpos1_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
+../fonts/gpos1_1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos1_1_simple.tests b/test/shape/data/aots/tests/gpos1_1_simple.tests
index 6fd49fa09..013796297 100644
--- a/test/shape/data/aots/tests/gpos1_1_simple.tests
+++ b/test/shape/data/aots/tests/gpos1_1_simple.tests
@@ -1,4 +1,4 @@
-../fonts/gpos1_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
-../fonts/gpos1_1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,-200|19@3000,0|20@4500,-200|21@6000,0]
-../fonts/gpos1_1_simple_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@2800,0|20@4300,0|21@5600,0]
-#../fonts/gpos1_1_simple_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,-200|20@4500,-200|21@6000,-400]
+../fonts/gpos1_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
+../fonts/gpos1_1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,-200|19@3000,0|20@4500,-200|21@6000,0]
+../fonts/gpos1_1_simple_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@2800,0|20@4300,0|21@5600,0]
+#../fonts/gpos1_1_simple_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,-200|20@4500,-200|21@6000,-400]
diff --git a/test/shape/data/aots/tests/gpos1_2.tests b/test/shape/data/aots/tests/gpos1_2.tests
index c8d949dbc..6dbb577f0 100644
--- a/test/shape/data/aots/tests/gpos1_2.tests
+++ b/test/shape/data/aots/tests/gpos1_2.tests
@@ -1 +1 @@
-../fonts/gpos1_2_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4200,0|21@6000,0]
+../fonts/gpos1_2_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos1_2_lookupflag.tests b/test/shape/data/aots/tests/gpos1_2_lookupflag.tests
index e2c694f22..41579a700 100644
--- a/test/shape/data/aots/tests/gpos1_2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos1_2_lookupflag.tests
@@ -1 +1 @@
-../fonts/gpos1_2_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
+../fonts/gpos1_2_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos2_1.tests b/test/shape/data/aots/tests/gpos2_1.tests
index ca946050d..bafdc8585 100644
--- a/test/shape/data/aots/tests/gpos2_1.tests
+++ b/test/shape/data/aots/tests/gpos2_1.tests
@@ -1,2 +1,2 @@
-../fonts/gpos2_1_font6.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0]
-../fonts/gpos2_1_font7.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011,U+0015,U+0016,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0|21@10000,0|22@12000,-600|17@13500,0]
+../fonts/gpos2_1_font6.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0]
+../fonts/gpos2_1_font7.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011,U+0015,U+0016,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0|21@10000,0|22@12000,-600|17@13500,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_lookupflag.tests b/test/shape/data/aots/tests/gpos2_1_lookupflag.tests
index 0aacce0fb..e9d1babca 100644
--- a/test/shape/data/aots/tests/gpos2_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos2_1_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gpos2_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
-../fonts/gpos2_1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
+../fonts/gpos2_1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
+../fonts/gpos2_1_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_next_glyph.tests b/test/shape/data/aots/tests/gpos2_1_next_glyph.tests
index 990314d28..09b368f33 100644
--- a/test/shape/data/aots/tests/gpos2_1_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos2_1_next_glyph.tests
@@ -1,2 +1,2 @@
-../fonts/gpos2_1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
-../fonts/gpos2_1_next_glyph_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
+../fonts/gpos2_1_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
+../fonts/gpos2_1_next_glyph_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_simple.tests b/test/shape/data/aots/tests/gpos2_1_simple.tests
index 86c1b9a03..6c69a94a2 100644
--- a/test/shape/data/aots/tests/gpos2_1_simple.tests
+++ b/test/shape/data/aots/tests/gpos2_1_simple.tests
@@ -1,2 +1,2 @@
-../fonts/gpos2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
-../fonts/gpos2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
+../fonts/gpos2_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
+../fonts/gpos2_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
diff --git a/test/shape/data/aots/tests/gpos2_2.tests b/test/shape/data/aots/tests/gpos2_2.tests
index afcd6613d..6a3084c63 100644
--- a/test/shape/data/aots/tests/gpos2_2.tests
+++ b/test/shape/data/aots/tests/gpos2_2.tests
@@ -1,5 +1,5 @@
-../fonts/gpos2_2_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
-../fonts/gpos2_2_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
-../fonts/gpos2_2_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
-../fonts/gpos2_2_font4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
-../fonts/gpos2_2_font5.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
+../fonts/gpos2_2_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
+../fonts/gpos2_2_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
+../fonts/gpos2_2_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
+../fonts/gpos2_2_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
+../fonts/gpos2_2_font5.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shape/data/aots/tests/gpos3.tests b/test/shape/data/aots/tests/gpos3.tests
index 6981ec5c2..b7cb57958 100644
--- a/test/shape/data/aots/tests/gpos3.tests
+++ b/test/shape/data/aots/tests/gpos3.tests
@@ -1,11 +1,11 @@
-#../fonts/gpos3_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
-../fonts/gpos3_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@6000,0]
-#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0012,U+0011;[17|18@1500,0|18@1600,100|17@4500,0]
-#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
-#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0012,U+0011;[17|20@1500,0|18@1602,102|17@4500,0]
-#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0013,U+0011;[17|20@1500,0|19@1601,101|17@4500,0]
-../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0011;[17|18@1500,0|20@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0012,U+0011;[17|19@1500,0|18@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011;[17|19@1500,0|20@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
-../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0]
+#../fonts/gpos3_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
+../fonts/gpos3_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@6000,0]
+#../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0012,U+0011;[17|18@1500,0|18@1600,100|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0012,U+0011;[17|20@1500,0|18@1602,102|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0013,U+0011;[17|20@1500,0|19@1601,101|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0011;[17|18@1500,0|20@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0012,U+0011;[17|19@1500,0|18@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011;[17|19@1500,0|20@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
+../fonts/gpos3_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos3_lookupflag.tests b/test/shape/data/aots/tests/gpos3_lookupflag.tests
index c615f4e9c..936d936fe 100644
--- a/test/shape/data/aots/tests/gpos3_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos3_lookupflag.tests
@@ -1,2 +1,2 @@
-#../fonts/gpos3_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|19@1599,99|17@6000,0]
-#../fonts/gpos3_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0|19@1599,99|17@9000,0]
+#../fonts/gpos3_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|19@1599,99|17@6000,0]
+#../fonts/gpos3_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0|19@1599,99|17@9000,0]
diff --git a/test/shape/data/aots/tests/gpos4_lookupflag.tests b/test/shape/data/aots/tests/gpos4_lookupflag.tests
index e75ba84d8..5ca6e1a2b 100644
--- a/test/shape/data/aots/tests/gpos4_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos4_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gpos4_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@4500,0]
-../fonts/gpos4_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@3000,0|17@3000,0]
+../fonts/gpos4_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@4500,0]
+../fonts/gpos4_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@3000,0|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos4_multiple_anchors.tests b/test/shape/data/aots/tests/gpos4_multiple_anchors.tests
index 793041f52..9eddc026d 100644
--- a/test/shape/data/aots/tests/gpos4_multiple_anchors.tests
+++ b/test/shape/data/aots/tests/gpos4_multiple_anchors.tests
@@ -1 +1 @@
-#../fonts/gpos4_multiple_anchors_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0015,U+0016,U+0012,U+0013,U+0014,U+0015,U+0016;[17|19@-100,-80|20@-1591,-71|21@-3102,-82|22@-4593,-73|18@1500,0|19@1420,-60|20@-71,-51|21@-1582,-62|22@-3073,-53]
+#../fonts/gpos4_multiple_anchors_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0015,U+0016,U+0012,U+0013,U+0014,U+0015,U+0016;[17|19@-100,-80|20@-1591,-71|21@-3102,-82|22@-4593,-73|18@1500,0|19@1420,-60|20@-71,-51|21@-1582,-62|22@-3073,-53]
diff --git a/test/shape/data/aots/tests/gpos4_simple.tests b/test/shape/data/aots/tests/gpos4_simple.tests
index a25361cdc..37a63f07c 100644
--- a/test/shape/data/aots/tests/gpos4_simple.tests
+++ b/test/shape/data/aots/tests/gpos4_simple.tests
@@ -1,5 +1,5 @@
-#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
-../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
-../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0019,U+0019,U+0013,U+0011;[25|25@1500,0|19@3000,0|17@3000,0]
-#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0013,U+0011;[17|18@1500,0|19@1400,-80|19@-100,-80|17@3000,0]
-#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0013,U+0011;[17|18@1500,0|20@3000,0|19@-100,-80|17@3000,0]
+../fonts/gpos4_simple_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
+../fonts/gpos4_simple_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
+../fonts/gpos4_simple_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0019,U+0019,U+0013,U+0011;[25|25@1500,0|19@3000,0|17@3000,0]
+#../fonts/gpos4_simple_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0013,U+0011;[17|18@1500,0|19@1400,-80|19@-100,-80|17@3000,0]
+#../fonts/gpos4_simple_1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0013,U+0011;[17|18@1500,0|20@3000,0|19@-100,-80|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos5.tests b/test/shape/data/aots/tests/gpos5.tests
index d1462f4b2..85909545c 100644
--- a/test/shape/data/aots/tests/gpos5.tests
+++ b/test/shape/data/aots/tests/gpos5.tests
@@ -1,2 +1,2 @@
-../fonts/gpos5_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+0013,U+001F,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
-#../fonts/gpos5_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+001F,U+0013,U+0011;[17|18@1500,0|19@1401,-79|17@3000,0]
+../fonts/gpos5_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+0013,U+001F,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
+../fonts/gpos5_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+001F,U+0013,U+0011;[17|18@1500,0|19@1401,-79|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos6.tests b/test/shape/data/aots/tests/gpos6.tests
index b65c941af..27a2afa37 100644
--- a/test/shape/data/aots/tests/gpos6.tests
+++ b/test/shape/data/aots/tests/gpos6.tests
@@ -1,3 +1,3 @@
-#../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@-100,-80|17@1500,0]
-../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
-../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0014,U+0014,U+0013,U+0011;[20|20|19|17]
+#../fonts/gpos6_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@-100,-80|17@1500,0]
+../fonts/gpos6_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
+../fonts/gpos6_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0014,U+0014,U+0013,U+0011;[20|20|19|17]
diff --git a/test/shape/data/aots/tests/gpos7_1.tests b/test/shape/data/aots/tests/gpos7_1.tests
index ba773ba38..3fb28d8cb 100644
--- a/test/shape/data/aots/tests/gpos7_1.tests
+++ b/test/shape/data/aots/tests/gpos7_1.tests
@@ -1,2 +1,2 @@
-../fonts/gpos7_1_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1600,0|19@3200,0|20@4800,0|21@6000,0]
-../fonts/gpos7_1_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|17@3000,0|18@4500,0|19@6000,0|17@7500,0]
+../fonts/gpos7_1_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1600,0|19@3200,0|20@4800,0|21@6000,0]
+../fonts/gpos7_1_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|17@3000,0|18@4500,0|19@6000,0|17@7500,0]
diff --git a/test/shape/data/aots/tests/gpos9.tests b/test/shape/data/aots/tests/gpos9.tests
index 5a2bc90d8..84c2d4235 100644
--- a/test/shape/data/aots/tests/gpos9.tests
+++ b/test/shape/data/aots/tests/gpos9.tests
@@ -1,2 +1,2 @@
-../fonts/gpos9_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
-../fonts/gpos9_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015,U+0011;[17|18@1300,0|19@2700,0|20@4300,0|21@5700,0|17@7500,0]
+../fonts/gpos9_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
+../fonts/gpos9_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015,U+0011;[17|18@1300,0|19@2700,0|20@4300,0|21@5700,0|17@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_boundary.tests b/test/shape/data/aots/tests/gpos_chaining1_boundary.tests
index ab7e264a1..2841c31e9 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gpos_chaining1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests
index dd1034411..96db43f0f 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gpos_chaining1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests
index e4e37f7ad..e9e747e82 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_chaining1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
-../fonts/gpos_chaining1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining1_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining1_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests
index 4431e522b..c11060b37 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_chaining1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
+../fonts/gpos_chaining1_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_simple.tests b/test/shape/data/aots/tests/gpos_chaining1_simple.tests
index bdb61a9ad..03b037bd8 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_simple.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gpos_chaining1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
+../fonts/gpos_chaining1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_successive.tests b/test/shape/data/aots/tests/gpos_chaining1_successive.tests
index dba4fc327..a86924708 100644
--- a/test/shape/data/aots/tests/gpos_chaining1_successive.tests
+++ b/test/shape/data/aots/tests/gpos_chaining1_successive.tests
@@ -1 +1 @@
-../fonts/gpos_chaining1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
+../fonts/gpos_chaining1_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_boundary.tests b/test/shape/data/aots/tests/gpos_chaining2_boundary.tests
index e731ad9f4..78195fb5f 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gpos_chaining2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests
index 432dd9ea4..3f2551256 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests
@@ -1 +1 @@
-../fonts/gpos_chaining2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests
index d7374ad43..066f53fba 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_chaining2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
-../fonts/gpos_chaining2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining2_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining2_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests
index 30e9b7cd8..dbb353c27 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_chaining2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
+../fonts/gpos_chaining2_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_simple.tests b/test/shape/data/aots/tests/gpos_chaining2_simple.tests
index 2d1087179..41303d405 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_simple.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gpos_chaining2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
+../fonts/gpos_chaining2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_successive.tests b/test/shape/data/aots/tests/gpos_chaining2_successive.tests
index 069e85610..df30a0e95 100644
--- a/test/shape/data/aots/tests/gpos_chaining2_successive.tests
+++ b/test/shape/data/aots/tests/gpos_chaining2_successive.tests
@@ -1 +1 @@
-../fonts/gpos_chaining2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
+../fonts/gpos_chaining2_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_boundary.tests b/test/shape/data/aots/tests/gpos_chaining3_boundary.tests
index aa846d09d..f93e2e691 100644
--- a/test/shape/data/aots/tests/gpos_chaining3_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_chaining3_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gpos_chaining3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests
index 53b61b192..ea0f57eff 100644
--- a/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests
@@ -1 +1 @@
-../fonts/gpos_chaining3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests
index 29eb1abc9..ea985a6df 100644
--- a/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_chaining3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22@1500,0|21@3020,0|22@4500,0|21@6020,0|22@7500,0|21@9000,0|0@10500,0]
+../fonts/gpos_chaining3_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22@1500,0|21@3020,0|22@4500,0|21@6020,0|22@7500,0|21@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_simple.tests b/test/shape/data/aots/tests/gpos_chaining3_simple.tests
index 3a96de7fd..648a4d50b 100644
--- a/test/shape/data/aots/tests/gpos_chaining3_simple.tests
+++ b/test/shape/data/aots/tests/gpos_chaining3_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gpos_chaining3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
+../fonts/gpos_chaining3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_successive.tests b/test/shape/data/aots/tests/gpos_chaining3_successive.tests
index ddddf4751..d98d6fed3 100644
--- a/test/shape/data/aots/tests/gpos_chaining3_successive.tests
+++ b/test/shape/data/aots/tests/gpos_chaining3_successive.tests
@@ -1 +1 @@
-../fonts/gpos_chaining3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
+../fonts/gpos_chaining3_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_boundary.tests b/test/shape/data/aots/tests/gpos_context1_boundary.tests
index 39e27496f..ea4c3513c 100644
--- a/test/shape/data/aots/tests/gpos_context1_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_context1_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
+../fonts/gpos_context1_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context1_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_expansion.tests b/test/shape/data/aots/tests/gpos_context1_expansion.tests
index e8105d315..63681e91d 100644
--- a/test/shape/data/aots/tests/gpos_context1_expansion.tests
+++ b/test/shape/data/aots/tests/gpos_context1_expansion.tests
@@ -1 +1 @@
-../fonts/gpos_context1_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
+../fonts/gpos_context1_expansion_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_lookupflag.tests b/test/shape/data/aots/tests/gpos_context1_lookupflag.tests
index 2120eb3a0..408284029 100644
--- a/test/shape/data/aots/tests/gpos_context1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_context1_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
-../fonts/gpos_context1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
+../fonts/gpos_context1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context1_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests
index 78e7a3bb8..551997be9 100644
--- a/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
-../fonts/gpos_context1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context1_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context1_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_next_glyph.tests b/test/shape/data/aots/tests/gpos_context1_next_glyph.tests
index 4bcd32791..b3d7cf2a0 100644
--- a/test/shape/data/aots/tests/gpos_context1_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_context1_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_context1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context1_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_simple.tests b/test/shape/data/aots/tests/gpos_context1_simple.tests
index 5353a54df..9b3c28bc3 100644
--- a/test/shape/data/aots/tests/gpos_context1_simple.tests
+++ b/test/shape/data/aots/tests/gpos_context1_simple.tests
@@ -1,3 +1,3 @@
-../fonts/gpos_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
-../fonts/gpos_context1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
+../fonts/gpos_context1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_successive.tests b/test/shape/data/aots/tests/gpos_context1_successive.tests
index 285e14339..33a8c8067 100644
--- a/test/shape/data/aots/tests/gpos_context1_successive.tests
+++ b/test/shape/data/aots/tests/gpos_context1_successive.tests
@@ -1 +1 @@
-../fonts/gpos_context1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_context1_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_boundary.tests b/test/shape/data/aots/tests/gpos_context2_boundary.tests
index e93aa74e0..d46d96355 100644
--- a/test/shape/data/aots/tests/gpos_context2_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_context2_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
+../fonts/gpos_context2_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context2_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_classes.tests b/test/shape/data/aots/tests/gpos_context2_classes.tests
index d0fbc0db1..77884edd5 100644
--- a/test/shape/data/aots/tests/gpos_context2_classes.tests
+++ b/test/shape/data/aots/tests/gpos_context2_classes.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context2_classes_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20@1500,0|26@3020,0|28@4500,0|24@6000,0|0@7500,0|21@9000,0|27@10520,0|26@12000,0|24@13500,0|0@15000,0|22@16500,0|27@18000,0|26@19500,0|24@21000,0]
-../fonts/gpos_context2_classes_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22@1500,0|27@3020,0|26@4500,0|24@6000,0|0@7500,0|24@9000,0|24@10500,0|29@12020,0|22@13500,0|0@15000,0|22@16500,0|27@18020,0|26@19500,0|24@21000,0]
+../fonts/gpos_context2_classes_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20@1500,0|26@3020,0|28@4500,0|24@6000,0|0@7500,0|21@9000,0|27@10520,0|26@12000,0|24@13500,0|0@15000,0|22@16500,0|27@18000,0|26@19500,0|24@21000,0]
+../fonts/gpos_context2_classes_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22@1500,0|27@3020,0|26@4500,0|24@6000,0|0@7500,0|24@9000,0|24@10500,0|29@12020,0|22@13500,0|0@15000,0|22@16500,0|27@18020,0|26@19500,0|24@21000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_expansion.tests b/test/shape/data/aots/tests/gpos_context2_expansion.tests
index 74eb5ef35..10ef83ea0 100644
--- a/test/shape/data/aots/tests/gpos_context2_expansion.tests
+++ b/test/shape/data/aots/tests/gpos_context2_expansion.tests
@@ -1 +1 @@
-../fonts/gpos_context2_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
+../fonts/gpos_context2_expansion_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_lookupflag.tests b/test/shape/data/aots/tests/gpos_context2_lookupflag.tests
index a9432a3b5..be7c1f30b 100644
--- a/test/shape/data/aots/tests/gpos_context2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_context2_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
-../fonts/gpos_context2_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
+../fonts/gpos_context2_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context2_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests
index d02cddef5..4df79f5a1 100644
--- a/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
-../fonts/gpos_context2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context2_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context2_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_next_glyph.tests b/test/shape/data/aots/tests/gpos_context2_next_glyph.tests
index 57855bd4b..501fa8167 100644
--- a/test/shape/data/aots/tests/gpos_context2_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_context2_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_context2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context2_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_simple.tests b/test/shape/data/aots/tests/gpos_context2_simple.tests
index 15c65c2a0..4922d3e43 100644
--- a/test/shape/data/aots/tests/gpos_context2_simple.tests
+++ b/test/shape/data/aots/tests/gpos_context2_simple.tests
@@ -1,3 +1,3 @@
-../fonts/gpos_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
-../fonts/gpos_context2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
+../fonts/gpos_context2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_successive.tests b/test/shape/data/aots/tests/gpos_context2_successive.tests
index 9aba57f91..75478b401 100644
--- a/test/shape/data/aots/tests/gpos_context2_successive.tests
+++ b/test/shape/data/aots/tests/gpos_context2_successive.tests
@@ -1 +1 @@
-../fonts/gpos_context2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_context2_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_boundary.tests b/test/shape/data/aots/tests/gpos_context3_boundary.tests
index 29f0ec53c..02fa35149 100644
--- a/test/shape/data/aots/tests/gpos_context3_boundary.tests
+++ b/test/shape/data/aots/tests/gpos_context3_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
+../fonts/gpos_context3_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context3_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_lookupflag.tests b/test/shape/data/aots/tests/gpos_context3_lookupflag.tests
index e1cb329c8..39144b0b6 100644
--- a/test/shape/data/aots/tests/gpos_context3_lookupflag.tests
+++ b/test/shape/data/aots/tests/gpos_context3_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
-../fonts/gpos_context3_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
+../fonts/gpos_context3_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context3_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_next_glyph.tests b/test/shape/data/aots/tests/gpos_context3_next_glyph.tests
index b5e70baa6..98b40a87f 100644
--- a/test/shape/data/aots/tests/gpos_context3_next_glyph.tests
+++ b/test/shape/data/aots/tests/gpos_context3_next_glyph.tests
@@ -1 +1 @@
-../fonts/gpos_context3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context3_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_simple.tests b/test/shape/data/aots/tests/gpos_context3_simple.tests
index 228afc1b6..4ac7be648 100644
--- a/test/shape/data/aots/tests/gpos_context3_simple.tests
+++ b/test/shape/data/aots/tests/gpos_context3_simple.tests
@@ -1,2 +1,2 @@
-../fonts/gpos_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0|20@9020,0|21@10520,0|22@12020,0|0@13500,0]
+../fonts/gpos_context3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0|20@9020,0|21@10520,0|22@12020,0|0@13500,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_successive.tests b/test/shape/data/aots/tests/gpos_context3_successive.tests
index 658222d9a..a761f3cde 100644
--- a/test/shape/data/aots/tests/gpos_context3_successive.tests
+++ b/test/shape/data/aots/tests/gpos_context3_successive.tests
@@ -1 +1 @@
-../fonts/gpos_context3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_context3_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gsub1_1_lookupflag.tests b/test/shape/data/aots/tests/gsub1_1_lookupflag.tests
index 3f5722b41..bdb077588 100644
--- a/test/shape/data/aots/tests/gsub1_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub1_1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub1_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|24|20|21]
+../fonts/gsub1_1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|24|20|21]
diff --git a/test/shape/data/aots/tests/gsub1_1_modulo.tests b/test/shape/data/aots/tests/gsub1_1_modulo.tests
index d716f18e5..933a16f6b 100644
--- a/test/shape/data/aots/tests/gsub1_1_modulo.tests
+++ b/test/shape/data/aots/tests/gsub1_1_modulo.tests
@@ -1 +1 @@
-../fonts/gsub1_1_modulo_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018;[17|18|17|24|23|18|23|24]
+../fonts/gsub1_1_modulo_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018;[17|18|17|24|23|18|23|24]
diff --git a/test/shape/data/aots/tests/gsub1_1_simple.tests b/test/shape/data/aots/tests/gsub1_1_simple.tests
index 11649be29..038bffc60 100644
--- a/test/shape/data/aots/tests/gsub1_1_simple.tests
+++ b/test/shape/data/aots/tests/gsub1_1_simple.tests
@@ -1 +1 @@
-../fonts/gsub1_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
+../fonts/gsub1_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
diff --git a/test/shape/data/aots/tests/gsub1_2_lookupflag.tests b/test/shape/data/aots/tests/gsub1_2_lookupflag.tests
index 13e523d75..1ec51696b 100644
--- a/test/shape/data/aots/tests/gsub1_2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub1_2_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub1_2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|25|21]
+../fonts/gsub1_2_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|25|21]
diff --git a/test/shape/data/aots/tests/gsub1_2_simple.tests b/test/shape/data/aots/tests/gsub1_2_simple.tests
index 372c3e61f..1b6450605 100644
--- a/test/shape/data/aots/tests/gsub1_2_simple.tests
+++ b/test/shape/data/aots/tests/gsub1_2_simple.tests
@@ -1 +1 @@
-../fonts/gsub1_2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|22|19|25|21]
+../fonts/gsub1_2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|22|19|25|21]
diff --git a/test/shape/data/aots/tests/gsub2_1_lookupflag.tests b/test/shape/data/aots/tests/gsub2_1_lookupflag.tests
index 178d5d6e4..30a988887 100644
--- a/test/shape/data/aots/tests/gsub2_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub2_1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub2_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|18|22|23|17]
+../fonts/gsub2_1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|18|22|23|17]
diff --git a/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests b/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests
index 394a9a7af..e14e8bed4 100644
--- a/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests
+++ b/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests
@@ -1 +1 @@
-../fonts/gsub2_1_multiple_sequences_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|20|21|22|23|17]
+../fonts/gsub2_1_multiple_sequences_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|20|21|22|23|17]
diff --git a/test/shape/data/aots/tests/gsub2_1_simple.tests b/test/shape/data/aots/tests/gsub2_1_simple.tests
index 817d92e35..ca9b85c86 100644
--- a/test/shape/data/aots/tests/gsub2_1_simple.tests
+++ b/test/shape/data/aots/tests/gsub2_1_simple.tests
@@ -1,2 +1,2 @@
-../fonts/gsub2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013;[17|20|21|22|19]
-../fonts/gsub2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0012;[17|20|21|22|19|20|21|22]
+../fonts/gsub2_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013;[17|20|21|22|19]
+../fonts/gsub2_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0012;[17|20|21|22|19|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub3_1_lookupflag.tests b/test/shape/data/aots/tests/gsub3_1_lookupflag.tests
index 8233f0e4d..4789bb73a 100644
--- a/test/shape/data/aots/tests/gsub3_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub3_1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub3_1_lookupflag_f1.otf;--features="-test[4],test[5],test[6]=2,-test[7]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|18|18|19|22|23|19|17]
+../fonts/gsub3_1_lookupflag_f1.otf;--features="-test[4],test[5],test[6]=2,-test[7]" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|18|18|19|22|23|19|17]
diff --git a/test/shape/data/aots/tests/gsub3_1_multiple.tests b/test/shape/data/aots/tests/gsub3_1_multiple.tests
index 47311aa1c..5f82cce6d 100644
--- a/test/shape/data/aots/tests/gsub3_1_multiple.tests
+++ b/test/shape/data/aots/tests/gsub3_1_multiple.tests
@@ -1 +1 @@
-../fonts/gsub3_1_multiple_f1.otf;--features="-test[1],test[2],test[3]=2,-test[4],-test[5],test[6],test[7]=2,-test[8]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|20|21|18|19|22|23|19|17]
+../fonts/gsub3_1_multiple_f1.otf;--features="-test[1],test[2],test[3]=2,-test[4],-test[5],test[6],test[7]=2,-test[8]" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|20|21|18|19|22|23|19|17]
diff --git a/test/shape/data/aots/tests/gsub3_1_simple.tests b/test/shape/data/aots/tests/gsub3_1_simple.tests
index 2b9d7d14b..ee920514b 100644
--- a/test/shape/data/aots/tests/gsub3_1_simple.tests
+++ b/test/shape/data/aots/tests/gsub3_1_simple.tests
@@ -1 +1 @@
-../fonts/gsub3_1_simple_f1.otf;--features="-test[1],test[3],test[5]=2,test[7]=3,-test[9],test[11]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011;[17|18|17|20|17|21|17|22|17|18|17|20|17]
+../fonts/gsub3_1_simple_f1.otf;--features="-test[1],test[3],test[5]=2,test[7]=3,-test[9],test[11]" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011;[17|18|17|20|17|21|17|22|17|18|17|20|17]
diff --git a/test/shape/data/aots/tests/gsub4_1_lookupflag.tests b/test/shape/data/aots/tests/gsub4_1_lookupflag.tests
index d65a59a0e..e54d9fb56 100644
--- a/test/shape/data/aots/tests/gsub4_1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub4_1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub4_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0018,U+0012,U+0018,U+0013,U+0018,U+0018,U+0014,U+0018,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|23|24|24|24|24|17|18|19|22|20]
+../fonts/gsub4_1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0018,U+0012,U+0018,U+0013,U+0018,U+0018,U+0014,U+0018,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|23|24|24|24|24|17|18|19|22|20]
diff --git a/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests b/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests
index c96d72263..c1a82a700 100644
--- a/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests
+++ b/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests
@@ -1,2 +1,2 @@
-../fonts/gsub4_1_multiple_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|24|22|20]
-../fonts/gsub4_1_multiple_ligatures_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|20|17|24|22|20]
+../fonts/gsub4_1_multiple_ligatures_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|24|22|20]
+../fonts/gsub4_1_multiple_ligatures_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|20|17|24|22|20]
diff --git a/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests b/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests
index e3f24373d..58a874f75 100644
--- a/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests
+++ b/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests
@@ -1 +1 @@
-../fonts/gsub4_1_multiple_ligsets_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0015,U+0014,U+0013,U+0016;[17|23|21|24|22]
+../fonts/gsub4_1_multiple_ligsets_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0015,U+0014,U+0013,U+0016;[17|23|21|24|22]
diff --git a/test/shape/data/aots/tests/gsub4_1_simple.tests b/test/shape/data/aots/tests/gsub4_1_simple.tests
index 0e5638393..c5d6e9049 100644
--- a/test/shape/data/aots/tests/gsub4_1_simple.tests
+++ b/test/shape/data/aots/tests/gsub4_1_simple.tests
@@ -1 +1 @@
-../fonts/gsub4_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|18|19|22|20]
+../fonts/gsub4_1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|18|19|22|20]
diff --git a/test/shape/data/aots/tests/gsub7.tests b/test/shape/data/aots/tests/gsub7.tests
index 46bba7f7e..c40c3af75 100644
--- a/test/shape/data/aots/tests/gsub7.tests
+++ b/test/shape/data/aots/tests/gsub7.tests
@@ -1,2 +1,2 @@
-../fonts/gsub7_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
-../fonts/gsub7_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|29|20|21]
+../fonts/gsub7_font1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
+../fonts/gsub7_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|29|20|21]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_boundary.tests b/test/shape/data/aots/tests/gsub_chaining1_boundary.tests
index 43f37be5f..34408ef9a 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gsub_chaining1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
-../fonts/gsub_chaining1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining1_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining1_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
+../fonts/gsub_chaining1_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining1_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining1_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining1_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests
index 685cf192c..a999517b7 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub_chaining1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
+../fonts/gsub_chaining1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests
index 6a0993a37..39a1564dc 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_chaining1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
-../fonts/gsub_chaining1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining1_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining1_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests
index f66f5e25d..859acbab5 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_chaining1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
+../fonts/gsub_chaining1_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_simple.tests b/test/shape/data/aots/tests/gsub_chaining1_simple.tests
index f812b55a7..757845dd4 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_simple.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gsub_chaining1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
-../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
+../fonts/gsub_chaining1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_successive.tests b/test/shape/data/aots/tests/gsub_chaining1_successive.tests
index 1dce9a141..80650e2ee 100644
--- a/test/shape/data/aots/tests/gsub_chaining1_successive.tests
+++ b/test/shape/data/aots/tests/gsub_chaining1_successive.tests
@@ -1 +1 @@
-../fonts/gsub_chaining1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
+../fonts/gsub_chaining1_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_boundary.tests b/test/shape/data/aots/tests/gsub_chaining2_boundary.tests
index eacd1d562..f7796d8fb 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gsub_chaining2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
-../fonts/gsub_chaining2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining2_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining2_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
+../fonts/gsub_chaining2_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining2_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining2_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining2_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests
index a368e23c7..4296f8ffd 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub_chaining2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
+../fonts/gsub_chaining2_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests
index 7e5403376..47a725cc6 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_chaining2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
-../fonts/gsub_chaining2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining2_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining2_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests
index 350902be9..f986b4621 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_chaining2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
+../fonts/gsub_chaining2_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_simple.tests b/test/shape/data/aots/tests/gsub_chaining2_simple.tests
index 1cdb9f897..a3c392bb3 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_simple.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gsub_chaining2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
-../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
+../fonts/gsub_chaining2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_successive.tests b/test/shape/data/aots/tests/gsub_chaining2_successive.tests
index ab872a4a0..609b2fca7 100644
--- a/test/shape/data/aots/tests/gsub_chaining2_successive.tests
+++ b/test/shape/data/aots/tests/gsub_chaining2_successive.tests
@@ -1 +1 @@
-../fonts/gsub_chaining2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
+../fonts/gsub_chaining2_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_boundary.tests b/test/shape/data/aots/tests/gsub_chaining3_boundary.tests
index a9ce26442..ec12f5e7b 100644
--- a/test/shape/data/aots/tests/gsub_chaining3_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_chaining3_boundary.tests
@@ -1,4 +1,4 @@
-../fonts/gsub_chaining3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
-../fonts/gsub_chaining3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining3_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
-../fonts/gsub_chaining3_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
+../fonts/gsub_chaining3_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining3_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining3_boundary_f3.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining3_boundary_f4.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests
index ef6682ebc..12632f7a9 100644
--- a/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests
@@ -1 +1 @@
-../fonts/gsub_chaining3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
+../fonts/gsub_chaining3_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests
index 6245fa94e..22f7fde2f 100644
--- a/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_chaining3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22|61|22|61|22|21|0]
+../fonts/gsub_chaining3_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22|61|22|61|22|21|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_simple.tests b/test/shape/data/aots/tests/gsub_chaining3_simple.tests
index b930260f1..8201338f0 100644
--- a/test/shape/data/aots/tests/gsub_chaining3_simple.tests
+++ b/test/shape/data/aots/tests/gsub_chaining3_simple.tests
@@ -1,11 +1,11 @@
-../fonts/gsub_chaining3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
-../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
+../fonts/gsub_chaining3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_successive.tests b/test/shape/data/aots/tests/gsub_chaining3_successive.tests
index d8d34df4d..1776858fc 100644
--- a/test/shape/data/aots/tests/gsub_chaining3_successive.tests
+++ b/test/shape/data/aots/tests/gsub_chaining3_successive.tests
@@ -1 +1 @@
-../fonts/gsub_chaining3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
+../fonts/gsub_chaining3_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_boundary.tests b/test/shape/data/aots/tests/gsub_context1_boundary.tests
index 22de4e025..2244b91c0 100644
--- a/test/shape/data/aots/tests/gsub_context1_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_context1_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
-../fonts/gsub_context1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
+../fonts/gsub_context1_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context1_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_expansion.tests b/test/shape/data/aots/tests/gsub_context1_expansion.tests
index c31f5154b..98d6f1f99 100644
--- a/test/shape/data/aots/tests/gsub_context1_expansion.tests
+++ b/test/shape/data/aots/tests/gsub_context1_expansion.tests
@@ -1 +1 @@
-../fonts/gsub_context1_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
+../fonts/gsub_context1_expansion_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_lookupflag.tests b/test/shape/data/aots/tests/gsub_context1_lookupflag.tests
index 57cd90022..2795b9df0 100644
--- a/test/shape/data/aots/tests/gsub_context1_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_context1_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
-../fonts/gsub_context1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
+../fonts/gsub_context1_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context1_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests
index 6ade72230..0c3b06d6a 100644
--- a/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
-../fonts/gsub_context1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
+../fonts/gsub_context1_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
+../fonts/gsub_context1_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_next_glyph.tests b/test/shape/data/aots/tests/gsub_context1_next_glyph.tests
index 824f0684c..2b97147fc 100644
--- a/test/shape/data/aots/tests/gsub_context1_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_context1_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_context1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
+../fonts/gsub_context1_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_simple.tests b/test/shape/data/aots/tests/gsub_context1_simple.tests
index 496eee6c6..55ae682b6 100644
--- a/test/shape/data/aots/tests/gsub_context1_simple.tests
+++ b/test/shape/data/aots/tests/gsub_context1_simple.tests
@@ -1,3 +1,3 @@
-../fonts/gsub_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
-../fonts/gsub_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
-../fonts/gsub_context1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
+../fonts/gsub_context1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context1_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
+../fonts/gsub_context1_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_successive.tests b/test/shape/data/aots/tests/gsub_context1_successive.tests
index a04b437f3..9e8793a97 100644
--- a/test/shape/data/aots/tests/gsub_context1_successive.tests
+++ b/test/shape/data/aots/tests/gsub_context1_successive.tests
@@ -1 +1 @@
-../fonts/gsub_context1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
+../fonts/gsub_context1_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_boundary.tests b/test/shape/data/aots/tests/gsub_context2_boundary.tests
index 65963af43..cd6319b31 100644
--- a/test/shape/data/aots/tests/gsub_context2_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_context2_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
-../fonts/gsub_context2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
+../fonts/gsub_context2_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context2_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_classes.tests b/test/shape/data/aots/tests/gsub_context2_classes.tests
index eac17b1dc..b392a8c28 100644
--- a/test/shape/data/aots/tests/gsub_context2_classes.tests
+++ b/test/shape/data/aots/tests/gsub_context2_classes.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context2_classes_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20|66|28|24|0|21|67|26|24|0|22|27|26|24]
-../fonts/gsub_context2_classes_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22|67|26|24|0|24|24|69|22|0|22|67|26|24]
+../fonts/gsub_context2_classes_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20|66|28|24|0|21|67|26|24|0|22|27|26|24]
+../fonts/gsub_context2_classes_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22|67|26|24|0|24|24|69|22|0|22|67|26|24]
diff --git a/test/shape/data/aots/tests/gsub_context2_expansion.tests b/test/shape/data/aots/tests/gsub_context2_expansion.tests
index 4c3711896..b95ee0ac7 100644
--- a/test/shape/data/aots/tests/gsub_context2_expansion.tests
+++ b/test/shape/data/aots/tests/gsub_context2_expansion.tests
@@ -1 +1 @@
-../fonts/gsub_context2_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
+../fonts/gsub_context2_expansion_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_lookupflag.tests b/test/shape/data/aots/tests/gsub_context2_lookupflag.tests
index a4d229dd5..8c4bbb1d1 100644
--- a/test/shape/data/aots/tests/gsub_context2_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_context2_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
-../fonts/gsub_context2_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
+../fonts/gsub_context2_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context2_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests
index 22495b8ea..74d248f8b 100644
--- a/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests
+++ b/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
-../fonts/gsub_context2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
+../fonts/gsub_context2_multiple_subrules_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
+../fonts/gsub_context2_multiple_subrules_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_next_glyph.tests b/test/shape/data/aots/tests/gsub_context2_next_glyph.tests
index ea2fad26a..dbd6f7a0c 100644
--- a/test/shape/data/aots/tests/gsub_context2_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_context2_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_context2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
+../fonts/gsub_context2_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_simple.tests b/test/shape/data/aots/tests/gsub_context2_simple.tests
index c58947ba0..f7d6e1017 100644
--- a/test/shape/data/aots/tests/gsub_context2_simple.tests
+++ b/test/shape/data/aots/tests/gsub_context2_simple.tests
@@ -1,3 +1,3 @@
-../fonts/gsub_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
-../fonts/gsub_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
-../fonts/gsub_context2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
+../fonts/gsub_context2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context2_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
+../fonts/gsub_context2_simple_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_successive.tests b/test/shape/data/aots/tests/gsub_context2_successive.tests
index 7ccdecfd3..7b19b53a1 100644
--- a/test/shape/data/aots/tests/gsub_context2_successive.tests
+++ b/test/shape/data/aots/tests/gsub_context2_successive.tests
@@ -1 +1 @@
-../fonts/gsub_context2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
+../fonts/gsub_context2_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_boundary.tests b/test/shape/data/aots/tests/gsub_context3_boundary.tests
index 7ad6fcb32..4a14b1391 100644
--- a/test/shape/data/aots/tests/gsub_context3_boundary.tests
+++ b/test/shape/data/aots/tests/gsub_context3_boundary.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
-../fonts/gsub_context3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
+../fonts/gsub_context3_boundary_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context3_boundary_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_lookupflag.tests b/test/shape/data/aots/tests/gsub_context3_lookupflag.tests
index 3cdc87e5e..c47ace9e3 100644
--- a/test/shape/data/aots/tests/gsub_context3_lookupflag.tests
+++ b/test/shape/data/aots/tests/gsub_context3_lookupflag.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
-../fonts/gsub_context3_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
+../fonts/gsub_context3_lookupflag_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context3_lookupflag_f2.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_next_glyph.tests b/test/shape/data/aots/tests/gsub_context3_next_glyph.tests
index 462019a56..15b10fcaa 100644
--- a/test/shape/data/aots/tests/gsub_context3_next_glyph.tests
+++ b/test/shape/data/aots/tests/gsub_context3_next_glyph.tests
@@ -1 +1 @@
-../fonts/gsub_context3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
+../fonts/gsub_context3_next_glyph_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_simple.tests b/test/shape/data/aots/tests/gsub_context3_simple.tests
index d1b628aec..7b9ee74e6 100644
--- a/test/shape/data/aots/tests/gsub_context3_simple.tests
+++ b/test/shape/data/aots/tests/gsub_context3_simple.tests
@@ -1,2 +1,2 @@
-../fonts/gsub_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
-../fonts/gsub_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|0|20|21|0|60|61|62|0]
+../fonts/gsub_context3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context3_simple_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|0|20|21|0|60|61|62|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_successive.tests b/test/shape/data/aots/tests/gsub_context3_successive.tests
index 99ec25683..f10a22d1c 100644
--- a/test/shape/data/aots/tests/gsub_context3_successive.tests
+++ b/test/shape/data/aots/tests/gsub_context3_successive.tests
@@ -1 +1 @@
-../fonts/gsub_context3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
+../fonts/gsub_context3_successive_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_attach.tests b/test/shape/data/aots/tests/lookupflag_ignore_attach.tests
index 16a22e044..8544114f9 100644
--- a/test/shape/data/aots/tests/lookupflag_ignore_attach.tests
+++ b/test/shape/data/aots/tests/lookupflag_ignore_attach.tests
@@ -1,5 +1,5 @@
-../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+000D,U+001A,U+000A;[10|15|10]
-../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+0017,U+001D,U+001A,U+000A;[10|15|21|22|23|29|10]
-../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+001B,U+001A,U+000A;[10|11|21|13|22|27|26|10]
-../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+0016,U+0017,U+001A,U+000A;[10|11|27|13|22|23|26|10]
-../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+000E,U+0017,U+001A,U+000A;[10|11|27|13|14|23|26|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+000D,U+001A,U+000A;[10|15|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+0017,U+001D,U+001A,U+000A;[10|15|21|22|23|29|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+001B,U+001A,U+000A;[10|11|21|13|22|27|26|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+0016,U+0017,U+001A,U+000A;[10|11|27|13|22|23|26|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+000E,U+0017,U+001A,U+000A;[10|11|27|13|14|23|26|10]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_base.tests b/test/shape/data/aots/tests/lookupflag_ignore_base.tests
index ba4f7309a..bf4c5cdd3 100644
--- a/test/shape/data/aots/tests/lookupflag_ignore_base.tests
+++ b/test/shape/data/aots/tests/lookupflag_ignore_base.tests
@@ -1,2 +1,2 @@
-../fonts/lookupflag_ignore_base_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|21]
-../fonts/lookupflag_ignore_base_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0018,U+0018,U+0013,U+0019,U+0014,U+0015;[17|23|24|24|25|21]
+../fonts/lookupflag_ignore_base_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|21]
+../fonts/lookupflag_ignore_base_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0018,U+0018,U+0013,U+0019,U+0014,U+0015;[17|23|24|24|25|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_combination.tests b/test/shape/data/aots/tests/lookupflag_ignore_combination.tests
index 08b5b48b1..062618d4c 100644
--- a/test/shape/data/aots/tests/lookupflag_ignore_combination.tests
+++ b/test/shape/data/aots/tests/lookupflag_ignore_combination.tests
@@ -1,3 +1,3 @@
-../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0014,U+0015;[17|23|26|21]
-../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+001F,U+0014,U+0015;[17|23|26|24|30|31|21]
-../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+0020,U+0014,U+0015;[17|18|26|19|24|30|32|20|21]
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0014,U+0015;[17|23|26|21]
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+001F,U+0014,U+0015;[17|23|26|24|30|31|21]
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+0020,U+0014,U+0015;[17|18|26|19|24|30|32|20|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests b/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests
index b5238155f..ef7e377a3 100644
--- a/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests
+++ b/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests
@@ -1,3 +1,3 @@
-../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+001B,U+0013,U+001B,U+0014,U+0015;[17|23|26|27|27|21]
-../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0018,U+0013,U+001B,U+0014,U+0015;[17|18|26|24|19|27|20|21]
-../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+002A,U+0013,U+001B,U+0014,U+0015;[17|18|26|42|19|27|20|21]
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+001B,U+0013,U+001B,U+0014,U+0015;[17|23|26|27|27|21]
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0018,U+0013,U+001B,U+0014,U+0015;[17|18|26|24|19|27|20|21]
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+002A,U+0013,U+001B,U+0014,U+0015;[17|18|26|42|19|27|20|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_marks.tests b/test/shape/data/aots/tests/lookupflag_ignore_marks.tests
index de1ccf20b..df7faa4d9 100644
--- a/test/shape/data/aots/tests/lookupflag_ignore_marks.tests
+++ b/test/shape/data/aots/tests/lookupflag_ignore_marks.tests
@@ -1 +1 @@
-../fonts/lookupflag_ignore_marks_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001C,U+001D,U+0013,U+001D,U+0014,U+0015;[17|23|28|29|29|21]
+../fonts/lookupflag_ignore_marks_f1.otf;--features="test" --single-par --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001C,U+001D,U+0013,U+001D,U+0014,U+0015;[17|23|28|29|29|21]
diff --git a/test/shape/data/in-house/Makefile.am b/test/shape/data/in-house/Makefile.am
index a2845785e..2ecf1fb29 100644
--- a/test/shape/data/in-house/Makefile.am
+++ b/test/shape/data/in-house/Makefile.am
@@ -14,10 +14,18 @@ EXTRA_DIST = \
$(NULL)
TEST_EXTENSIONS = .tests
+TESTS_ENVIRONMENT =
if HAVE_FREETYPE
-TESTS_ENVIRONMENT = HAVE_FREETYPE=1
-else
-TESTS_ENVIRONMENT = HAVE_FREETYPE=0
+TESTS_ENVIRONMENT += HAVE_FREETYPE=1
+endif
+if HAVE_CORETEXT
+TESTS_ENVIRONMENT += HAVE_CORETEXT=1
+endif
+if HAVE_DIRECTWRITE
+TESTS_ENVIRONMENT += HAVE_DIRECTWRITE=1
+endif
+if HAVE_UNISCRIBE
+TESTS_ENVIRONMENT += HAVE_UNISCRIBE=1
endif
TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
diff --git a/test/shape/data/in-house/Makefile.sources b/test/shape/data/in-house/Makefile.sources
index 2432d89fb..58b6732d7 100644
--- a/test/shape/data/in-house/Makefile.sources
+++ b/test/shape/data/in-house/Makefile.sources
@@ -7,25 +7,32 @@ TESTS = \
tests/arabic-mark-attach.tests \
tests/arabic-mark-order.tests \
tests/arabic-normalization.tests \
+ tests/arabic-phags-pa.tests \
tests/arabic-stch.tests \
tests/automatic-fractions.tests \
tests/cluster.tests \
tests/collections.tests \
tests/color-fonts.tests \
tests/context-matching.tests \
+ tests/coretext.tests \
tests/cursive-positioning.tests \
tests/default-ignorables.tests \
tests/digits.tests \
+ tests/directwrite.tests \
tests/emoji.tests \
tests/emoji-clusters.tests \
tests/fallback-positioning.tests \
+ tests/glyph-props-no-gdef.tests \
tests/hangul-jamo.tests \
+ tests/hebrew-diacritics.tests \
tests/hyphens.tests \
tests/indic-consonant-with-stacker.tests \
tests/indic-decompose.tests \
+ tests/indic-feature-order.tests \
tests/indic-init.tests \
tests/indic-joiner-candrabindu.tests \
tests/indic-joiners.tests \
+ tests/indic-malayalam-dot-reph.tests \
tests/indic-old-spec.tests \
tests/indic-pref-blocking.tests \
tests/indic-script-extensions.tests \
@@ -45,11 +52,13 @@ TESTS = \
tests/myanmar-misc.tests \
tests/myanmar-syllable.tests \
tests/myanmar-zawgyi.tests \
+ tests/nested-mark-filtering-sets.tests \
tests/none-directional.tests \
tests/positioning-features.tests \
tests/rand.tests \
tests/reverse-sub.tests \
tests/rotation.tests \
+ tests/sara-am.tests \
tests/simple.tests \
tests/sinhala.tests \
tests/spaces.tests \
@@ -57,7 +66,10 @@ TESTS = \
tests/tibetan-contractions-2.tests \
tests/tibetan-vowels.tests \
tests/tt-kern-gpos.tests \
+ tests/uniscribe.tests \
+ tests/unsafe-to-concat.tests \
tests/use-indic3.tests \
+ tests/use-javanese.tests \
tests/use-marchen.tests \
tests/use-syllable.tests \
tests/use-vowel-letter-spoofing.tests \
diff --git a/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf b/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf
new file mode 100644
index 000000000..134e7dd41
--- /dev/null
+++ b/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf b/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf
new file mode 100644
index 000000000..3c8d4483c
--- /dev/null
+++ b/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf b/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf
new file mode 100644
index 000000000..e88a9afbf
--- /dev/null
+++ b/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf b/test/shape/data/in-house/fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf
new file mode 100644
index 000000000..8508fbeeb
--- /dev/null
+++ b/test/shape/data/in-house/fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf b/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf
new file mode 100644
index 000000000..ebb6f6480
--- /dev/null
+++ b/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf b/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf
new file mode 100644
index 000000000..9834a2e66
--- /dev/null
+++ b/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf b/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf
new file mode 100644
index 000000000..2d2bf19b1
--- /dev/null
+++ b/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf b/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf
new file mode 100644
index 000000000..f94d2aa84
--- /dev/null
+++ b/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf b/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf
new file mode 100644
index 000000000..055a836e5
--- /dev/null
+++ b/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf b/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf
new file mode 100644
index 000000000..af8052d63
--- /dev/null
+++ b/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf b/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf
new file mode 100644
index 000000000..cc60a075b
--- /dev/null
+++ b/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf b/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf
new file mode 100644
index 000000000..9c9f9426a
--- /dev/null
+++ b/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/FallbackPlus-Javanese-no-GDEF.otf b/test/shape/data/in-house/fonts/FallbackPlus-Javanese-no-GDEF.otf
new file mode 100644
index 000000000..45896c104
--- /dev/null
+++ b/test/shape/data/in-house/fonts/FallbackPlus-Javanese-no-GDEF.otf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/NotoNastaliqUrdu-Regular.ttf b/test/shape/data/in-house/fonts/NotoNastaliqUrdu-Regular.ttf
new file mode 100644
index 000000000..cd01de0d1
--- /dev/null
+++ b/test/shape/data/in-house/fonts/NotoNastaliqUrdu-Regular.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/SimpArabicTest.ttf b/test/shape/data/in-house/fonts/SimpArabicTest.ttf
new file mode 100644
index 000000000..d560f6a38
--- /dev/null
+++ b/test/shape/data/in-house/fonts/SimpArabicTest.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/TradArabicTest.ttf b/test/shape/data/in-house/fonts/TradArabicTest.ttf
new file mode 100644
index 000000000..a82ed3575
--- /dev/null
+++ b/test/shape/data/in-house/fonts/TradArabicTest.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf b/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf
new file mode 100644
index 000000000..e0325bb0c
--- /dev/null
+++ b/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf b/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf
new file mode 100644
index 000000000..31f8731cc
--- /dev/null
+++ b/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf b/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf
new file mode 100644
index 000000000..da5255f24
--- /dev/null
+++ b/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf b/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf
new file mode 100644
index 000000000..ff0129bde
--- /dev/null
+++ b/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf b/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf
new file mode 100644
index 000000000..81978690b
--- /dev/null
+++ b/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf b/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf
new file mode 100644
index 000000000..6786f7c4c
--- /dev/null
+++ b/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf b/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf
new file mode 100644
index 000000000..80c97d3dd
--- /dev/null
+++ b/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf b/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf
new file mode 100644
index 000000000..c9311cfbd
--- /dev/null
+++ b/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf
Binary files differ
diff --git a/test/shape/data/in-house/meson.build b/test/shape/data/in-house/meson.build
index 70b1a1cc9..e396073f3 100644
--- a/test/shape/data/in-house/meson.build
+++ b/test/shape/data/in-house/meson.build
@@ -7,25 +7,32 @@ in_house_tests = [
'arabic-mark-attach.tests',
'arabic-mark-order.tests',
'arabic-normalization.tests',
+ 'arabic-phags-pa.tests',
'arabic-stch.tests',
'automatic-fractions.tests',
'cluster.tests',
'collections.tests',
'color-fonts.tests',
'context-matching.tests',
+ 'coretext.tests',
'cursive-positioning.tests',
'default-ignorables.tests',
'digits.tests',
+ 'directwrite.tests',
'emoji.tests',
'emoji-clusters.tests',
'fallback-positioning.tests',
+ 'glyph-props-no-gdef.tests',
'hangul-jamo.tests',
+ 'hebrew-diacritics.tests',
'hyphens.tests',
'indic-consonant-with-stacker.tests',
'indic-decompose.tests',
+ 'indic-feature-order.tests',
'indic-init.tests',
'indic-joiner-candrabindu.tests',
'indic-joiners.tests',
+ 'indic-malayalam-dot-reph.tests',
'indic-old-spec.tests',
'indic-pref-blocking.tests',
'indic-script-extensions.tests',
@@ -45,11 +52,13 @@ in_house_tests = [
'myanmar-misc.tests',
'myanmar-syllable.tests',
'myanmar-zawgyi.tests',
+ 'nested-mark-filtering-sets.tests',
'none-directional.tests',
'positioning-features.tests',
'rand.tests',
'reverse-sub.tests',
'rotation.tests',
+ 'sara-am.tests',
'simple.tests',
'sinhala.tests',
'spaces.tests',
@@ -57,7 +66,10 @@ in_house_tests = [
'tibetan-contractions-2.tests',
'tibetan-vowels.tests',
'tt-kern-gpos.tests',
+ 'uniscribe.tests',
+ 'unsafe-to-concat.tests',
'use-indic3.tests',
+ 'use-javanese.tests',
'use-marchen.tests',
'use-syllable.tests',
'use-vowel-letter-spoofing.tests',
diff --git a/test/shape/data/in-house/tests/arabic-fallback-shaping.tests b/test/shape/data/in-house/tests/arabic-fallback-shaping.tests
index 14f89198b..ac087899c 100644
--- a/test/shape/data/in-house/tests/arabic-fallback-shaping.tests
+++ b/test/shape/data/in-house/tests/arabic-fallback-shaping.tests
@@ -1 +1,11 @@
../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf;;U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC;[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@148,0+0|uni0651=2@187,736+0|uni064E=2@883,1259+0|uni0651=2@922,736+0|uni06440627.fina=2+1470|uni064F=0@629,-10+0|uni0633.init=0+1585]
+../fonts/SimpArabicTest.ttf;--no-positions;U+0628,U+0650,U+0633,U+0652,U+0645,U+0650,U+0020,U+0020,U+0627,U+0644,U+0644,U+0647,U+0020,U+0627,U+0644,U+0631,U+0651,U+064E,U+062D,U+0652,U+0645,U+064E,U+0646,U+0650,U+0020,U+0627,U+0644,U+0631,U+062D,U+0650,U+064A,U+0645;[daggerdbl=31|c142=30|twosuperior=28|bracketleft=28|c=27|quotedblbase=26|J=25|parenright=24|twosuperior=22|Eacute=22|logicalnot=20|dagger=20|registered=18|bracketleft=18|logicalnot=15|plusminus=15|c=15|quotedblbase=14|J=13|parenright=12|guilsinglleft=11|quotedblbase=10|quotedblbase=9|J=8|parenright=7|parenright=6|twosuperior=4|daggerdbl=4|registered=2|j=2|twosuperior=0|R=0]
+../fonts/SimpArabicTest.ttf;;U+0020,U+0644,U+0627,U+0020,U+0644,U+0623,U+0020,U+0644,U+064E,U+0623,U+064E,U+0020,U+0623,U+064E,U+0646,U+062A;[U=15+693|DEL=14+227|logicalnot=12@17,307+0|L=12+289|parenright=11+391|logicalnot=7@41,267+0|logicalnot=7@378,267+0|brokenbar=7+674|parenright=6+391|brokenbar=4+674|parenright=3+391|yen=1+709|parenright=0+391]
+../fonts/SimpArabicTest.ttf;;U+0021,U+0022,U+00AB,U+00BB,U+0025,U+00D7,U+00F7,U+0028,U+0020,U+0029,U+002A,U+002B,U+060C,U+002E,U+002F,U+003A,U+061B,U+2018,U+003D,U+2019,U+061F,U+005B,U+005D,U+002D,U+0022;[asterisk=0+269|plus=1+408|comma=2+509|hyphen=3+509|period=4+573|slash=5+572|zero=6+572|one=7+300|parenright=8+391|two=9+300|three=10+551|four=11+572|five=12+283|seven=13+268|eight=14+372|C=15+268|D=16+295|E=17+175|F=18+572|G=19+175|H=20+485|d=21+329|f=22+329|six=23+322|plus=24+408]
+../fonts/SimpArabicTest.ttf;;U+061F,U+003F,U+0640;[H=0+485|H=1+485|h=2+171]
+../fonts/SimpArabicTest.ttf;;U+0628,U+0644,U+0627,U+0020,U+0628,U+0644,U+0625;[ordfeminine=5+674|R=4+232|parenright=3+391|yen=1+709|R=0+232]
+../fonts/TradArabicTest.ttf;;U+0628,U+0650,U+0633,U+0652,U+0645,U+0650,U+0020,U+0020,U+0627,U+0644,U+0644,U+0647,U+0020,U+0627,U+0644,U+0631,U+0651,U+064E,U+062D,U+0652,U+0645,U+064E,U+0646,U+0650,U+0020,U+0627,U+0644,U+0631,U+062D,U+0650,U+064A,U+0645;[fnmeem=31+1069|midya=30+499|kasrah2=28@151,0+0|inhaa=28+1341|fnra=27+702|inlam=26+358|alef=25+444|righttoleftspace=24+468|kasrah2=22@110,-604+0|fnnoon=22+1259|fathah2=18@-145,-168+0|sukun2=18@760,-166+0|f29b=18+1497|fahtanonshaddah2=15@-51,-416+0|fnra=15+702|inlam=14+358|alef=13+444|righttoleftspace=12+468|Allah=9+1513|alef=8+444|righttoleftspace=7+468|righttoleftspace=6+468|kasrah2=4@15,-1102+0|fnmeem=4+1069|sukun2=2@220,-386+0|midseen=2+1163|kasrah2=0@-324,-403+0|inbaa=0+389]
+../fonts/TradArabicTest.ttf;;U+0020,U+0644,U+0627,U+0020,U+0644,U+0623,U+0020,U+0644,U+064E,U+0623,U+064E,U+0020,U+0623,U+064E,U+0646,U+062A;[fntaa=15+1808|innoon=14+389|fathah2=12@-279,883+0|hamzahonalef=12+479|righttoleftspace=11+468|fathah2=7@-190,862+0|fathah2=7@468,862+0|hamzahonlamelef=7+1316|righttoleftspace=6+468|hamzahonlamelef=4+1316|righttoleftspace=3+468|lamelef=1+1316|righttoleftspace=0+468]
+../fonts/TradArabicTest.ttf;;U+0021,U+0022,U+00AB,U+00BB,U+0025,U+00D7,U+00F7,U+0028,U+0020,U+0029,U+002A,U+002B,U+060C,U+002E,U+002F,U+003A,U+061B,U+2018,U+003D,U+2019,U+061F,U+005B,U+005D,U+002D,U+0022;[greater=0+481|question=1+559|at=2+849|A=3+849|percentarabic=4+1353|C=5+927|D=6+1196|E=7+855|righttoleftspace=8+468|F=9+855|G=10+884|H=11+1083|commaarabic=12+755|K=13+649|L=14+704|W=15+450|semicolonarabic=16+755|.notdef=17+745|Z=18+1128|.notdef=19+745|questionarabic=20+845|x=21+739|z=22+739|J=23+753|question=24+559]
+../fonts/TradArabicTest.ttf;;U+061F,U+003F,U+0640;[questionarabic=0+845|questionarabic=1+845|tatweelnarrow=2+378]
+../fonts/TradArabicTest.ttf;;U+0644,U+0645,U+0020,U+0628,U+0645,U+0627;[fnalef=5+468|f296=3+897|righttoleftspace=2+468|f205=0+903]
diff --git a/test/shape/data/in-house/tests/arabic-phags-pa.tests b/test/shape/data/in-house/tests/arabic-phags-pa.tests
new file mode 100644
index 000000000..76e0b285a
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-phags-pa.tests
@@ -0,0 +1,14 @@
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A873,U+A861;[uniA873=0+563|uniA861=1+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+A873,U+A861;[uniA861=0+463|uniA873=1+563|uniA861=2+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85E,U+A85E,U+A85E,U+0020,U+A85E;[uniA85E.ini=0+761|uniA85E.med=1+536|uniA85E.fin=2+446|space=3+260|uniA85E=4+671]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85F,U+A85F,U+A85F,U+0020,U+A85F;[uniA85F.ini=0+945|uniA85F.med=1+558|uniA85F.fin=2+502|space=3+260|uniA85F=4+842]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A860,U+A860,U+A860,U+0020,U+A860;[uniA860.ini=0+820|uniA860.med=1+510|uniA860.fin=2+420|space=3+260|uniA860=4+730]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+A861,U+A861,U+0020,U+A861;[uniA861.ini=0+553|uniA861.med=1+449|uniA861.fin=2+337|space=3+260|uniA861=4+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+200D,U+A861,U+200D;[space=0+0|uniA861.med=1+449|space=1+0]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+200D,U+A861;[space=0+0|uniA861.fin=1+337]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+200D;[uniA861.ini=0+553|space=0+0]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85E,U+200C,U+A85F,U+200C,U+A860,U+200C,U+A861;[uniA85E=0+671|space=1+0|uniA85F=2+842|space=3+0|uniA860=4+730|space=5+0|uniA861=6+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A849,U+A85E;[uniA849.ini=0+798|uniA85E.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A849,U+A85E,U+FE00;[uniA849.ini=0+798|uniA85E.mir.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A86A,U+A85E;[uniA86A.ini=0+798|uniA85E.mir.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A86A,U+A85E,U+FE00;[uniA86A.ini.unmir=0+766|uniA85E.fin=1+446]
diff --git a/test/shape/data/in-house/tests/collections.tests b/test/shape/data/in-house/tests/collections.tests
index 50d6d922e..defdb2b3a 100644
--- a/test/shape/data/in-house/tests/collections.tests
+++ b/test/shape/data/in-house/tests/collections.tests
@@ -1,6 +1,6 @@
../fonts/DFONT.dfont;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
-../fonts/DFONT.dfont;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
-../fonts/DFONT.dfont;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/DFONT.dfont;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
+../fonts/DFONT.dfont;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
../fonts/TTC.ttc;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
../fonts/TTC.ttc;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
-../fonts/TTC.ttc;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/TTC.ttc;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
diff --git a/test/shape/data/in-house/tests/context-matching.tests b/test/shape/data/in-house/tests/context-matching.tests
index ad71721e3..b0d66fffa 100644
--- a/test/shape/data/in-house/tests/context-matching.tests
+++ b/test/shape/data/in-house/tests/context-matching.tests
@@ -1,3 +1,5 @@
../fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf;;U+1A48,U+1A58,U+1A25,U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63;[uni1A48=0+1212|uni1A25=0+1912|uni1A58=0+0|uni1A48=3+1212|uni1A6E=3+0|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
../fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf;;U+0915,U+093F,U+0915,U+093F;[ivowelsign03deva=0+530|kadeva=0+1561|ivowelsign03deva=2+530|kadeva=2+1561]
../fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf;;U+09B0,U+09CD,U+09A5,U+09CD,U+09AF,U+09C0;[gid1=0+1320|gid13=0+523|gid18=0+545]
+../fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf;;U+1F1FA,U+1F1FC;[gid3=0+2550]
+../fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf;;U+0041,U+0042;[gid4=0+1366|gid4=0+1366|gid4=0+1366|gid4=0+1366|gid5=1+1366]
diff --git a/test/shape/data/in-house/tests/coretext.tests b/test/shape/data/in-house/tests/coretext.tests
new file mode 100644
index 000000000..4cecf4779
--- /dev/null
+++ b/test/shape/data/in-house/tests/coretext.tests
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=coretext;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
diff --git a/test/shape/data/in-house/tests/cursive-positioning.tests b/test/shape/data/in-house/tests/cursive-positioning.tests
index aca4fbad6..4d7709864 100644
--- a/test/shape/data/in-house/tests/cursive-positioning.tests
+++ b/test/shape/data/in-house/tests/cursive-positioning.tests
@@ -3,3 +3,14 @@
#../fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf;;U+0B1F,U+0B4D,U+0B1A,U+0B4D,U+0B1A;[ttaorya=0+1307|casubscriptorya=0@-242,104+-231|casubscriptnarroworya=0@20,104+507]
../fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf;--font-funcs=ot --no-glyph-names;U+0606,U+06E1;[2=0@40,502+0|1=0+1000]
../fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf;;U+16F0A,U+16F57,U+16F8F;[u16F0A=0+422|u16F57=0@0,209+338|u16F8F=0+0]
+
+# These are different from what Uniscribe does.
+# https://github.com/harfbuzz/harfbuzz/issues/2469
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+313|u1BC36=2+313|u1BC36=3+313|u1BC36=4+313]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=rtl1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1@0,432+218|u1BC36=2@-82,288+136|u1BC36=3@-82,144+136|u1BC36=4@-82,0+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,rtl1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1@0,432+218|u1BC36=2@-82,288+136|u1BC36=3@-82,144+136|u1BC36=4@-82,0+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=rtl1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,rtl1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
diff --git a/test/shape/data/in-house/tests/directwrite.tests b/test/shape/data/in-house/tests/directwrite.tests
new file mode 100644
index 000000000..334f234f6
--- /dev/null
+++ b/test/shape/data/in-house/tests/directwrite.tests
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=directwrite;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
diff --git a/test/shape/data/in-house/tests/emoji-clusters.tests b/test/shape/data/in-house/tests/emoji-clusters.tests
index be6a4e1ca..82511a366 100644
--- a/test/shape/data/in-house/tests/emoji-clusters.tests
+++ b/test/shape/data/in-house/tests/emoji-clusters.tests
@@ -44,6 +44,36 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FD;[1=0|1=0]
@@ -70,6 +100,11 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FD;[1=0|1=0]
@@ -116,6 +151,11 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FD;[1=0|1=0]
@@ -156,6 +196,11 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FD;[1=0|1=0]
@@ -166,6 +211,31 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FD;[1=0|1=0]
@@ -1156,6 +1226,11 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FD;[1=0|1=0]
@@ -1268,6 +1343,16 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FD;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FE;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FF;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FB;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FC;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FD;[1=0|1=0]
@@ -2781,6 +2866,7 @@
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F43B,200D,2744,FE0F;[1=0|1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F43B,200D,2744;[1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F54A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F426,200D,2B1B;[1=0|1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F577,FE0F;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F578,FE0F;[1=0|1=0]
../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F5,FE0F;[1=0|1=0]
diff --git a/test/shape/data/in-house/tests/glyph-props-no-gdef.tests b/test/shape/data/in-house/tests/glyph-props-no-gdef.tests
new file mode 100644
index 000000000..27bcbd530
--- /dev/null
+++ b/test/shape/data/in-house/tests/glyph-props-no-gdef.tests
@@ -0,0 +1 @@
+../fonts/FallbackPlus-Javanese-no-GDEF.otf;;U+A995,U+A9BF;[glyph01=0+600|uniA995=0+600]
diff --git a/test/shape/data/in-house/tests/hebrew-diacritics.tests b/test/shape/data/in-house/tests/hebrew-diacritics.tests
new file mode 100644
index 000000000..6f6aaf62d
--- /dev/null
+++ b/test/shape/data/in-house/tests/hebrew-diacritics.tests
@@ -0,0 +1,31 @@
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E7,U+05D5,U+05DC;[lamed=2+901|vav=1+484|kof=0+997]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D3,U+05D5,U+05D3,U+05D9;[yod=3+454|dalet=2+879|vav=1+484|dalet=0+879]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05E0,U+05D4,U+05BE,U+05D6,U+05D4;[he=5+1071|zain=4+549|makaf=3+631|he=2+1071|nun=1+614|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05D0;[alef=1+1048|bet=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05D3,U+05DC,U+05D2;[gimel=3+665|lamed=2+901|dalet=1+879|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E2,U+05DC,U+05BE,U+05D4,U+05D4,U+05E8,U+05D9,U+05DD;[finalmem=7+1004|yod=6+454|resh=5+883|he=4+1071|he=3+1071|makaf=2+631|lamed=1+901|ayin=0+920]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05E7,U+05E4,U+05E5;[finaltsadi=3+990|pe=2+912|kof=1+997|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E2,U+05DC,U+05BE,U+05D4,U+05D2,U+05D1,U+05E2,U+05D5,U+05EA;[tav=8+1026|vav=7+484|ayin=6+920|bet=5+967|gimel=4+665|he=3+1071|makaf=2+631|lamed=1+901|ayin=0+920]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05B2,U+05D1,U+05B5,U+05DC;[lamed=4+901|tsere=2@512,0+0|bet=2+967|hatafpatah=0@600,0+0|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05B2,U+05D1,U+05B8,U+05DC,U+05B4,U+05D9,U+05DD;[finalmem=7+1004|yod=6+454|hiriq=4@499,0+0|lamed=4+901|qamats=2@512,0+0|bet=2+967|hatafpatah=0@600,0+0|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05DE,U+05B7,U+05E8;[resh=4+883|patah=2@573,0+0|mem=2+1094|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E7,U+05B9,U+05D4,U+05B6,U+05DC,U+05B6,U+05EA;[tav=6+1026|segol=4@499,0+0|lamed=4+901|segol=2@597,0+0|he=2+1071|holam=0@482,0+0|kof=0+997]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DC,U+05B0,U+05D4,U+05B7,U+05D2,U+05BC,U+05B4,U+05D9,U+05D3;[dalet=8+879|yod=7+454|hiriq=4@360,0+0|gimeldagesh=4+665|patah=2@597,0+0|he=2+1071|sheva=0@499,0+0|lamed=0+901]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05BC,U+05B7,U+05D1,U+05BC,U+05B9,U+05E7,U+05B6,U+05E8;[resh=8+883|segol=6@618,0+0|kof=6+997|holam=3@422,0+0|betdagesh=3+967|patah=0@505,0+0|betdagesh=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D7,U+05B7,U+05E1,U+05B0,U+05D3,U+05BC,U+05B6,U+05DA,U+05B8;[finalkafqamats=7+846|segol=4@685,0+0|daleddagesh=4+879|sheva=2@581,0+0|samekh=2+1038|patah=0@594,0+0|het=0+1065]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D5,U+05B6,U+05D0,U+05B1,U+05DE,U+05D5,U+05BC,U+05E0,U+05B8,U+05EA,U+05B0,U+05DA,U+05B8;[finalkafqamats=11+846|sheva=9@587,0+0|tav=9+1026|qamats=7@316,0+0|nun=7+614|vavdagesh=5+510|mem=4+1094|hatafsegol=2@591,0+0|alef=2+1048|segol=0@349,0+0|vav=0+484]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05BC,U+05B7,U+05DC,U+05BC,U+05B5,U+05D9,U+05DC,U+05D5,U+05B9,U+05EA;[tav=10+1026|vavholam=8+484|lamed=7+901|yod=6+454|tsere=3@430,0+0|lameddagesh=3+901|patah=0@505,0+0|betdagesh=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B7,U+05B4,U+05DD;[finalmem=11+1004|hiriq=8@-97,0+0|patah=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B8,U+05B4,U+05DD;[finalmem=11+1004|hiriq=8@-97,0+0|qamats=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B7,U+05B0,U+05DE,U+05B8,U+05D4;[he=13+1071|qamats=11@573,0+0|mem=11+1094|sheva=8@177,0+0|patah=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B8,U+05B0,U+05DE,U+05B8,U+05D4;[he=13+1071|qamats=11@573,0+0|mem=11+1094|sheva=8@176,0+0|qamats=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E0,U+05B0,U+05D1,U+05BB,U+05BD,U+05DB,U+05B7,U+05D3,U+05B0,U+05E0,U+05B6,U+05D0,U+05E6,U+05BC,U+05B7,U+05A3,U+05E8;[resh=16+883|munah=12@203,0+0|patah=12@588,0+0|tsadidagesh=12+968|alef=11+1048|segol=9@316,0+0|nun=9+614|sheva=7@621,0+0|dalet=7+879|patah=5@469,0+0|kaf=5+942|meteg=2@338,0+0|qubuts=2@673,0+0|bet=2+967|sheva=0@316,0+0|nun=0+614]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05B4,U+05EA,U+05BC,U+05B8,U+0591,U+034F,U+05B7,U+059C,U+05D7,U+05B7,U+05EA;[tav=11+1026|patah=9@594,0+0|het=9+1065|gereshaccent=2+0|patah=2+0|space=2+0|atnah=2@437,0+0|qamats=2@794,0+0|tavdagesh=2+1026|hiriq=0@573,0+0|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B2,U+200D,U+05BD,U+05AD,U+05D3,U+05B7,U+05D1,U+05BC,U+05B0,U+05E8,U+05B8,U+05D4;[he=12+1071|qamats=10@719,0+0|resh=10+883|sheva=7@505,0+0|betdagesh=7+967|patah=5@621,0+0|dalet=5+879|dehi=0@1063,0+0|hatafpatah_meteg=0@593,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D5,U+05BD,U+034F,U+05B7,U+05D9,U+05B0,U+05D4,U+05B4,U+05D9,U+05BE,U+05AF,U+05DB,U+05B5,U+05BD,U+05DF;[finalnun=14+459|meteg=11@311,0+0|tsere=11@617,0+0|kaf=11+942|masoracircle=9@320,0+0|makaf=9+631|yod=8+454|hiriq=6@597,0+0|he=6+1071|sheva=4@239,0+0|yod=4+454|patah=0+0|space=0+0|meteg=0@349,0+0|vav=0+484]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DC,U+05C5,U+05C4,U+05D5,U+05BC,U+05DC,U+05B5,U+05C5,U+0597,U+05C4,U+05D0,U+05C5,U+05C4;[upperdot=10@594,0+0|lowerdot=10@594,0+0|alef=10+1048|upperdot=5@519,0+0|revia=5@601,0+0|lowerdot=5@519,0+0|tsere=5@499,0+0|lamed=5+901|vavdagesh=3+510|upperdot=0@519,0+0|lowerdot=0@519,0+0|lamed=0+901]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05E0,U+05BC,U+05B8,U+05BD,U+05D4;[he=6+1071|meteg=2@205,0+0|qamats=2@469,0+0|nundagesh=2+614|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05E0,U+05B8,U+05BC,U+05BD,U+05D4;[he=6+1071|meteg=2@205,0+0|qamats=2@469,0+0|nundagesh=2+614|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05EA,U+05B7,U+05E2,U+05B2,U+05E9,U+05B6,U+05C2,U+05A6,U+05D4;[he=8+1071|merkhakefula=4@353,0+0|segol=4@813,0+0|shinsindot=4+1292|hatafpatah=2@435,0+0|ayin.alt=2+920|patah=0@587,0+0|tav=0+1026]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E9,U+05B9,U+05BD,U+05C1,U+05D8,U+05B0,U+05E8,U+05B5,U+05D9,U+0599;[pashta=8@161,0+0|yod=8+454|tsere=6@719,0+0|resh=6+883|sheva=4@548,0+0|tet=4+1015|meteg=0@665,0+0|holam=0@362,0+0|shinshindot=0+1292]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B2,U+200D,U+05BD,U+05AD;[dehi=0@1063,0+0|hatafpatah_meteg=0@593,0+0|alef=0+1048]
diff --git a/test/shape/data/in-house/tests/indic-decompose.tests b/test/shape/data/in-house/tests/indic-decompose.tests
index 132011f58..c06dd35b7 100644
--- a/test/shape/data/in-house/tests/indic-decompose.tests
+++ b/test/shape/data/in-house/tests/indic-decompose.tests
@@ -1 +1 @@
-../fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf;--font-funcs=ot;U+09DC,U+0020,U+09DD,U+0020,U+09A1,U+09BC,U+0020,U+09A2,U+09BC;[bn_rha=0+1024|space=1+1024|bn_yya=2+1024|space=3+1024|bn_dda=4+1024|bn_nukta=4+1024|space=6+1024|bn_ddha=7+1024|bn_nukta=7+1024]
+../fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf;--font-funcs=ot;U+09DC,U+0020,U+09DD,U+0020,U+09A1,U+09BC,U+0020,U+09A2,U+09BC;[bn_rha=0+512|space=1+512|bn_yya=2+512|space=3+512|bn_dda=4+512|bn_nukta=4+512|space=6+512|bn_ddha=7+512|bn_nukta=7+512]
diff --git a/test/shape/data/in-house/tests/indic-feature-order.tests b/test/shape/data/in-house/tests/indic-feature-order.tests
new file mode 100644
index 000000000..5d5de9875
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-feature-order.tests
@@ -0,0 +1 @@
+../fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf;--features=ss03;U+0B95,U+0BC1;[uni0B95.ss03=0+1000|uni0BC1=0+0]
diff --git a/test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests b/test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests
new file mode 100644
index 000000000..c09caf17d
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests
@@ -0,0 +1,15 @@
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15;[kamlym=0+1038|rephmlym=0@-363,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D4D,U+0D30;[rapostmlym=0+200|kakamlym=0+1506|rephmlym=0@-657,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D28,U+0D4D,U+0D28;[nanamlym=0+1257|rephmlym=0@-507,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gagamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4B;[eevowelsignmlym=0+595|gamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17;[gamlym=0+897|rephmlym=0@-278,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gagamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30;[rapostmlym=0+239|gagamlym=0+897]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4B;[eevowelsignmlym=0+595|gagamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17;[gagamlym=0+897]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D41;[kamlym=0+1038|rephmlym=0@-363,0+0|uvowelsignmlym=0+332]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D41;[kakamlym=0+1506|rephmlym=0@-657,0+0|uvowelsignmlym=0+332]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D1A,U+0D4D,U+0D1A,U+0D4D;[cacamlym=0+933|viramamlym=0+0|rephmlym=0@-300,0+0]
diff --git a/test/shape/data/in-house/tests/indic-special-cases.tests b/test/shape/data/in-house/tests/indic-special-cases.tests
index 86106589a..d563dec11 100644
--- a/test/shape/data/in-house/tests/indic-special-cases.tests
+++ b/test/shape/data/in-house/tests/indic-special-cases.tests
@@ -1,3 +1,8 @@
../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+0CCD,U+0C95;[gid1=0+1176|gid5=0+1161]
../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+200D,U+0CCD,U+0C95;[gid2=0+1334|gid6=0+358]
../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+0CCD,U+200D,U+0C95;[gid2=0+1334|gid6=0+358]
+../fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf;;U+0C1A,U+0C3F,U+0C32,U+0C4D,U+0C15,U+0C42,U+0C30,U+0C4D;[civoweltelu=0+766|latelu=2+709|uuvowelsigntelu=2+661|kasubscripttelu=2+483|rahalanttelu=6+593]
+../fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf;;U+0915,U+093F,U+094E,U+093C;[uni094E=0+273|uni093C=0+0|ivowelsign03deva=0+259|uni0915=0+762]
+../fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf;;U+0915,U+093F,U+093C,U+094E;[uni094E=0+273|ivowelsign00deva=0+259|uni093C=0+0|uni0915=0+762]
+../fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf;;U+0A15,U+0A40,U+0A02;[uni0A15=0+505|uni0A40=0+427|uni0A02=0+0]
+../fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf;;U+0A15,U+0A02,U+0A40;[uni0A15=0+505|uni0A02=0+0|uni0A40=0+427]
diff --git a/test/shape/data/in-house/tests/indic-syllable.tests b/test/shape/data/in-house/tests/indic-syllable.tests
index 275fb1324..cc5c882f8 100644
--- a/test/shape/data/in-house/tests/indic-syllable.tests
+++ b/test/shape/data/in-house/tests/indic-syllable.tests
@@ -11,3 +11,4 @@
../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B55,U+0B3E;[uni0B2C=0+641|uni0B55=0+0|uni0B3E=0+253]
../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B3E,U+0B55;[uni0B2C=0+641|uni0B3E=0+253|uni0B55=0+0]
../fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf;;U+0BAA,U+0BAA,U+0BCD;[pa-tamil=0+778|pa-tamil.001=1+778|pulli-tamil=1@-385,0+0]
+../fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf;;U+0926,U+093F,U+0938,U+0902,U+092C,U+0930;[isigndeva=0+266|dadeva=0+541|sadeva=2+709|anusvaradeva=2@0,-1+0|badeva=4+537|radeva=5+436]
diff --git a/test/shape/data/in-house/tests/khmer-misc.tests b/test/shape/data/in-house/tests/khmer-misc.tests
index dff4fc115..4a7a580c8 100644
--- a/test/shape/data/in-house/tests/khmer-misc.tests
+++ b/test/shape/data/in-house/tests/khmer-misc.tests
@@ -88,3 +88,5 @@
../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+1784,U+17D2,U+1780;[uni17D2179A=0+287|uni17A0=0+928|uni17D2179C=0@20,-26+0|uni1784=5+635|uni17D21780=5@0,-26+0]
../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+17B6,U+17C6,U+1784;[uni17D2179A=0+287|uni17A017B6=0+1216|uni17D2179C=0@-268,-26+0|uni17C6=0@47,-29+0|uni1784=7+635]
../fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf;;U+17D2,U+17D2;[uni25CC=0+635|uni17D2=0+0|uni25CC=0+635|uni17D2=0+0]
+../fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf;;U+17C9;[uni25CC=0+655|uni17C9=0+0]
+../fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf;;U+17D9,U+17C9;[uni17D9=0+655|uni17C9=0+0]
diff --git a/test/shape/data/in-house/tests/ligature-id.tests b/test/shape/data/in-house/tests/ligature-id.tests
index 5fd582594..be4d232c5 100644
--- a/test/shape/data/in-house/tests/ligature-id.tests
+++ b/test/shape/data/in-house/tests/ligature-id.tests
@@ -35,3 +35,4 @@
../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf;;U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0020,U+0995,U+09CD,U+09B0,U+0995,U+09CD,U+09B2;[u0995_u09CD.half_u0995.pres=0+566|u0995_u09CD.half_u0995.pres=3+566|u0995_u09CD.half_u0995.pres=6+566|u0995_u09CD.half_u0995.pres=9+566|u0995_u09CD.half_u0995.pres=12+566|u0995_u09CD.half_u0995.pres=15+566|u0995_u09CD.half_u0995.pres=18+566|u0995_u09CD.half_u0995.pres=21+566|u0995_u09CD.half_u0995.pres=24+566|u0995_u09CD.half_u0995.pres=27+566|u0995_u09CD.half_u0995.pres=30+566|u0995_u09CD.half_u0995.pres=33+566|u0995_u09CD.half_u0995.pres=36+566|u0995_u09CD.half_u0995.pres=39+566|u0995_u09CD.half_u0995.pres=42+566|u0995_u09CD.half_u0995.pres=45+566|u0995_u09CD.half_u0995.pres=48+566|u0995_u09CD.half_u0995.pres=51+566|u0995_u09CD.half_u0995.pres=54+566|u0995_u09CD.half_u0995.pres=57+566|u0995_u09CD.half_u0995.pres=60+566|u0995_u09CD.half_u0995.pres=63+566|u0995_u09CD.half_u0995.pres=66+566|u0995_u09CD.half_u0995.pres=69+566|u0995_u09CD.half_u0995.pres=72+566|u0995_u09CD.half_u0995.pres=75+566|u0995_u09CD.half_u0995.pres=78+566|u0995_u09CD.half_u0995.pres=81+566|u0995_u09CD.half_u0995.pres=84+566|u0995_u09CD.half_u0995.pres=87+566|u0995_u09CD.half_u0995.pres=90+566|u0995_u09CD.half_u0995.pres=93+566|u0995_u09CD.half_u0995.pres=96+566|u0995_u09CD.half_u0995.pres=99+566|u0995_u09CD.half_u0995.pres=102+566|space=105+213|u0995_u09B0_u09CD.blwf.vatu=106+643|u0995_u09CD.half_u09B2.pres=109+602]
../fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf;;U+1004,U+103A,U+1039,U+101B,U+103D,U+102D;[uni101B103D=0+450|uni1004103A1039102D=0@-50,0+0]
../fonts/b31e6c52a31edadc16f1bec9efe6019e2d59824a.ttf;;U+0644,U+064E,U+0644,U+064F,U+0647;[LIG=0+1200|uni064F=0@-216,196+0|uni064E=0@233,46+0|lam_lam_hehar=0+1200]
+../fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf;;U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627;[dotabove-ar=24@188,546+0|fehDotless_alef-ar=24+752|space=23+0|dotabove-ar=21@588,546+0|fehDotless_alef-ar=21@400,0+1152|space=20+0|dotabove-ar=18@588,546+0|fehDotless_alef-ar=18@400,0+1152|space=17+0|dotabove-ar=15@588,546+0|fehDotless_alef-ar=15@400,0+1152|space=14+0|dotabove-ar=12@588,546+0|fehDotless_alef-ar=12@400,0+1152|space=11+0|dotabove-ar=9@588,546+0|fehDotless_alef-ar=9@400,0+1152|space=8+0|dotabove-ar=6@588,546+0|fehDotless_alef-ar=6@400,0+1152|space=5+0|dotabove-ar=3@588,546+0|fehDotless_alef-ar=3@400,0+1152|space=2+0|dotabove-ar=0@588,546+0|fehDotless_alef-ar=0@400,0+1152]
diff --git a/test/shape/data/in-house/tests/macos.tests b/test/shape/data/in-house/tests/macos.tests
index 7c7b806fb..d2f697027 100644
--- a/test/shape/data/in-house/tests/macos.tests
+++ b/test/shape/data/in-house/tests/macos.tests
@@ -1,3 +1,16 @@
+# https://github.com/harfbuzz/harfbuzz/issues/1373
+/System/Library/Fonts/Supplemental/BigCaslon.ttf;;U+0107;[cacute=0+432]
+/System/Library/Fonts/Supplemental/BigCaslon.ttf;--language=pl;U+0107;[cacute.polish=0+432]
+
+# https://github.com/harfbuzz/harfbuzz/issues/3314
+/System/Library/Fonts/Apple\ Color\ Emoji.ttc;--script=hebrew --direction ltr;U+1F1FA,U+1F1F8,U+1F1EE,U+1F1F1;[u1F1FA_u1F1F8=0+800|u1F1EE_u1F1F1=2+800]
+
+# https://github.com/harfbuzz/harfbuzz/issues/3528
+/System/Library/Fonts/Supplemental/Bangla MN.ttc;;U+09AC,U+09BF;[bn_ikaar=0+474|bn_ba=0+998]
+
+# https://github.com/harfbuzz/harfbuzz/issues/3535
+/System/Library/Fonts/LucidaGrande.ttc;;U+20DD,U+1F174,U+1F175;[circlecmb=0+0|.notdef=1+1536|.notdef=2+1536]
+
# https;//github.com/harfbuzz/harfbuzz/issues/3008
/System/Library/Fonts/ヒラギノ丸ゴ\ ProN\ W4.ttc;--features=palt;U+FF11;[gid781=0@-78,0+842]
@@ -116,6 +129,8 @@
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0631,U+0628;[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064F;[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+064E,U+0645,U+064E,U+0651,U+0627;[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+0627;[u0644_u0627.isolated.lamAlef=0+1162]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot --features rlig=0;U+0644,U+0627;[u0627.final.alef=1+647|u0644.initial.lam=0+515]
# SFNS uses opsz variation axis which isn't invoked here, see https;//crbug.com/1005969#c37
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0+920|e=1+1049|space=2+420|A=3+1162|V=4+1292|space=5+420|T=6+960|r=7+631|space=8+420|V=9+1142|a=10+1028|space=11+420|r=12+461|T=13+1190|space=14+420|e=15+779|T=16+1190|space=17+420|T=18+920|d=19+1134]
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-ptem 9 --font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0@19,0+958|e=1@19,0+1087|space=2@19,0+458|A=3@19,0+1200|V=4@19,0+1330|space=5@19,0+458|T=6@19,0+998|r=7@19,0+669|space=8@19,0+458|V=9@19,0+1180|a=10@19,0+1066|space=11@19,0+458|r=12@19,0+499|T=13@19,0+1228|space=14@19,0+458|e=15@19,0+817|T=16@19,0+1228|space=17@19,0+458|T=18@19,0+958|d=19@19,0+1172]
@@ -138,3 +153,6 @@
# 11.1
/System/Library/Fonts/Apple Color Emoji.ttc@6b0fa4926a1c8a32267e93e18c5eff21558de83a;--font-funcs ot;U+1F469,U+1F3FD,U+200D,U+1F91D,U+200D,U+1F468,U+1F3FE;[u1F469.3.L=0+0|space=0+0|space=0+0|u1F468.4.RA=0+800]
+
+# 12.3
+/System/Library/Fonts/Apple Color Emoji.ttc@8fa6ac4564651899da0b37d310d980db4de967d6;--font-funcs ot;1FAF1,1F3FF,200D,1FAF2,1F3FC;[u1FAF1.5.L=0+800|u1FAF2.2.R=0@-800,0+0]
diff --git a/test/shape/data/in-house/tests/myanmar-misc.tests b/test/shape/data/in-house/tests/myanmar-misc.tests
index 527386394..8ba0be472 100644
--- a/test/shape/data/in-house/tests/myanmar-misc.tests
+++ b/test/shape/data/in-house/tests/myanmar-misc.tests
@@ -1 +1,2 @@
../fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf;;U+101A,U+1035;[ya_e_above=0+1000]
+../fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf;;U+1000,U+1031,U+1084;[e_shn=0+592|_e=0+618|ka=0+1124]
diff --git a/test/shape/data/in-house/tests/nested-mark-filtering-sets.tests b/test/shape/data/in-house/tests/nested-mark-filtering-sets.tests
new file mode 100644
index 000000000..7de938289
--- /dev/null
+++ b/test/shape/data/in-house/tests/nested-mark-filtering-sets.tests
@@ -0,0 +1,4 @@
+../fonts/NotoNastaliqUrdu-Regular.ttf;;U+0628,U+0628,U+6D2;[OneDotBelowYB=2@764,-183+0|YBc1=2@764,-282+0|YehBarreeFin_3=2+355|OneDotBelowNS=1@20,-120+0|BehxMed.inT2outD2YB=1@0,349+182|NullMk=0+0|sp10=0+0|BehxIni.outT2=0@0,406+766]
+../fonts/NotoNastaliqUrdu-Regular.ttf;;U+0628,U+0628,U+0628,U+6D2;[OneDotBelowYB=3@764,-183+0|YBc1=3@764,-282+0|OneDotBelowYB=3@1098,-60+0|YBc2=3@1098,-159+0|YehBarreeFin_4=3+355|OneDotBelowNS=2@20,-120+0|BehxMed.inT2outD2YB=2@0,349+182|NullMk=1+0|BehxMed.inT1outT2=1@0,406+184|NullMk=0+0|sp5=0+0|BehxIni=0@0,471+541]
+../fonts/NotoNastaliqUrdu-Regular.ttf;;U+0628,U+0628,U+0628,U+0628,U+6D2;[OneDotBelowYB=4@659,-192+0|YBc1=4@659,-291+0|OneDotBelowYB=4@966,-55+0|YBc2=4@966,-154+0|OneDotBelowYB=4@1274,-148+0|YBc3=4@1274,-247+0|YehBarreeFin_5=4+355|OneDotBelowNS=3@20,-120+0|BehxMed.inT2outD2YB=3@0,349+182|NullMk=2+0|BehxMed.inT1outT2=2@0,406+184|NullMk=1+0|BehxMed.inT2outT1=1@0,471+267|NullMk=0+0|sp0=0+0|BehxIni.outT2=0@0,616+156]
+../fonts/NotoNastaliqUrdu-Regular.ttf;;U+0628,U+0628,U+0628,U+0628,U+0628,U+6D2;[OneDotBelowYB=5@659,-192+0|YBc1=5@659,-291+0|OneDotBelowYB=5@966,-55+0|YBc2=5@966,-154+0|OneDotBelowYB=5@1274,-148+0|YBc3=5@1274,-247+0|YehBarreeFin_5=5+355|OneDotBelowNS=4@20,-120+0|BehxMed.inT2outD2YB=4@0,349+182|NullMk=3+0|BehxMed.inT1outT2=3@0,406+184|NullMk=2+0|BehxMed.inT2outT1=2@0,471+267|NullMk=1+0|BehxMed.inT1outT2=1@0,616+184|OneDotBelowNS=0@73,516+0|sp0=0+0|BehxIni=0@0,681+236]
diff --git a/test/shape/data/in-house/tests/sara-am.tests b/test/shape/data/in-house/tests/sara-am.tests
new file mode 100644
index 000000000..32d749aa5
--- /dev/null
+++ b/test/shape/data/in-house/tests/sara-am.tests
@@ -0,0 +1,52 @@
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E31,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E31=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E34,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E34=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E35,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E35=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E36,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E36=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E37,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E37=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E47,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E47=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E48,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E48=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E49,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E49=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4A,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4A=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4B,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4B=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4C,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4C=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4D,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4D=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4E,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4E=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E31,U+0E4D,U+0E32;[uni0E01=0+500|uni0E31=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E34,U+0E4D,U+0E32;[uni0E01=0+500|uni0E34=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E35,U+0E4D,U+0E32;[uni0E01=0+500|uni0E35=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E36,U+0E4D,U+0E32;[uni0E01=0+500|uni0E36=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E37,U+0E4D,U+0E32;[uni0E01=0+500|uni0E37=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E47,U+0E4D,U+0E32;[uni0E01=0+500|uni0E47=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E48,U+0E4D,U+0E32;[uni0E01=0+500|uni0E48=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E49,U+0E4D,U+0E32;[uni0E01=0+500|uni0E49=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4A,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4A=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4B,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4B=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4C,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4C=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4D,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4D=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4E,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4E=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB1,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB1=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB4,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB4=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB5=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB5=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB7,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB7=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EBB,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EBB=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC8,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EC8=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC9,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EC9=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECA,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECA=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECB,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECB=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECC,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECC=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECD,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECD=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECE,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECE=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB1,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB1=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB4,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB4=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB5=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB5=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB7,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB7=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EBB,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EBB=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC8,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EC8=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC9,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EC9=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECA,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECA=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECB,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECB=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECC,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECC=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECD,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECD=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECE,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECE=0+0|uni0ECD=0+0|uni0EB2=3+500]
diff --git a/test/shape/data/in-house/tests/spaces.tests b/test/shape/data/in-house/tests/spaces.tests
index 36cfc0f0a..a73ab1405 100644
--- a/test/shape/data/in-house/tests/spaces.tests
+++ b/test/shape/data/in-house/tests/spaces.tests
@@ -15,20 +15,20 @@
../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+202F;[gid1=0+280]
../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+205F;[gid1=0+455]
../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+3000;[gid1=0+2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+0020;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+00A0;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+1680;[gid0=0@-346,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2000;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2001;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2002;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2003;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2004;[gid1=0@-280,0+0,-683]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2005;[gid1=0@-280,0+0,-512]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2006;[gid1=0@-280,0+0,-341]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2007;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2008;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2009;[gid1=0@-280,0+0,-410]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+200A;[gid1=0@-280,0+0,-128]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+202F;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+205F;[gid1=0@-280,0+0,-455]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+3000;[gid1=0@-280,0+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+0020;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+00A0;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+1680;[gid0=0@-346,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2000;[gid1=0@-280,-1263+0,-1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2001;[gid1=0@-280,-1263+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2002;[gid1=0@-280,-1263+0,-1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2003;[gid1=0@-280,-1263+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2004;[gid1=0@-280,-1263+0,-683]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2005;[gid1=0@-280,-1263+0,-512]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2006;[gid1=0@-280,-1263+0,-341]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2007;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2008;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2009;[gid1=0@-280,-1263+0,-410]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+200A;[gid1=0@-280,-1263+0,-128]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+202F;[gid1=0@-280,-1263+0,-1263]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+205F;[gid1=0@-280,-1263+0,-455]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+3000;[gid1=0@-280,-1263+0,-2048]
diff --git a/test/shape/data/in-house/tests/uniscribe.tests b/test/shape/data/in-house/tests/uniscribe.tests
new file mode 100644
index 000000000..9b563dbe5
--- /dev/null
+++ b/test/shape/data/in-house/tests/uniscribe.tests
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=uniscribe;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
diff --git a/test/shape/data/in-house/tests/unsafe-to-concat.tests b/test/shape/data/in-house/tests/unsafe-to-concat.tests
new file mode 100644
index 000000000..64381a3a5
--- /dev/null
+++ b/test/shape/data/in-house/tests/unsafe-to-concat.tests
@@ -0,0 +1 @@
+../fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf;--show-flags --unsafe-to-concat;U+0628,U+200C,U+0628;[uni0628=1+993#2|uni0628=0+993#2]
diff --git a/test/shape/data/in-house/tests/use-javanese.tests b/test/shape/data/in-house/tests/use-javanese.tests
new file mode 100644
index 000000000..bfebc7311
--- /dev/null
+++ b/test/shape/data/in-house/tests/use-javanese.tests
@@ -0,0 +1,54 @@
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA;[taling=0+677|pa=0+963]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A99F,U+A9C0,U+A9A2,U+A9BF;[da.pas_cakra=0+238|nna=0+1198]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA,U+A9B4,U+A982,U+A9A0,U+A9B8,U+A992,U+A9AD,U+A9C0;[taling=0+677|pa=0+963|layar.ns=0@-267,10+0|tarung=0+413|ta=4+1183|u.ns=4@-1,0+0|ga=6+938|la=7+1194|pangkon=7+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9CB;[uniA9CB=0+439]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+200B,U+A9C5;[space=0+0|uniA9C5=1+1981]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D1,U+A9D0,U+A9C7;[oneJV=0+938|zeroJV=1+605|uniA9C7=2+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D2,U+A9D0,U+A9D0,U+A9D4;[twoJV=0+977|zeroJV=1+605|zeroJV=2+605|fourJV=3+590]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D1,U+A9D8,U+A9D8,U+A9D5,U+A9C7;[oneJV=0+938|eightJV=1+1027|eightJV=2+1027|fiveJV=3+741|uniA9C7=4+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9A4,U+A9B6,U+A9A0,U+A9BF,U+A9C7;[pa=0+963|na=1+989|i.ns=1@-71,10+0|ta_cakra=3+1416|uniA9C7=5+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A98F,U+A9A0,U+A9BF,U+A981,U+A994,U+A9A4,U+A9C0;[ka=0+1221|ta_cakra=1+1416|cecak.ns=1@-306,10+0|nga=4+976|na=5+989|pangkon=5+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9C5,U+A9C9,U+A99F,U+A9C0,U+A9A2,U+A9BF,U+A9C9,U+A9C5;[uniA9C5=0+1981|uniA9C9=1+687|da.pas_cakra=2+238|nna=2+1198|uniA9C9=6+687|uniA9C5=7+1981]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA,U+A994,U+A9BC,U+A9A0,U+A9C0,U+A9A0,U+A9A4,U+A9C0;[taling=0+677|pa=0+963|nga=2+976|ae.ns=2@-63,10+0|ta=4+1183|ta.pas=4@-1,0+0|na=7+989|pangkon=7+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A984,U+A992,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9B8,U+A9B1,U+A9C0,U+A9C7;[akara=0+1338|ga=1+1221|u.ns=1@-283,0+0|sa=3+1088|ta.pas.alt=3+0|u.ns.pas=3+0|sa=7+1088|pangkon=7+391|uniA9C7=9+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9B8,U+A9AD,U+A9A4,U+A9C0,U+A997,U+A9A4,U+A9B8,U+A9AE,U+A9AB,U+A9B6;[wa=0+967|u.ns=0@-1,0+0|la=2+1194|na=3+989|ja.pas=3@200,0+0|na=6+989|u.ns=6+0|wa=8+967|ra=9+915|i.ns=9@-62,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+200B,U+A9AF,U+A9B6,U+A98F,U+A9BA,U+A995,U+A9B6;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|space=5+0|sha=6+938|i.ns=6@8,10+0|taling=8+677|ka=8+1221|ca=10+1043|i.ns=10@-1,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+200B,U+A9B1,U+A9B8,U+A982,U+A9AA,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|space=3+0|sa=4+1088|u.ns=4+0|layar.ns=4@-208,10+0|ya=7+1383|space=8+0|ka=9+1221|pa=10+963|i.ns_cecak.ns=10@-170,10+0|uniA9C7=13+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AF,U+A9BA,U+A99F,U+A9A6,U+A9A1,U+A9B6,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AD,U+A993,U+A9C8;[taling=0+677|sha=0+938|nna=2+1198|pha=3+1027|tha=4+967|i.ns=4@-61,10+0|space=6+0|ha=7+1195|i.ns_cecak.ns=7@-182,10+0|space=10+0|nga=11+976|la=12+1194|gha=13+1258|uniA9C8=14+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B8,U+A9A0,U+A9AE,U+A9B6,U+200B,U+A9AF,U+A9B8,U+A982,U+A9AA,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ha=0+1195|u.ns=0@-1,0+0|ta=2+1183|wa=3+967|i.ns=3@-61,10+0|space=5+0|sha=6+938|u.ns=6+0|layar.ns=6@-200,10+0|ya=9+1383|space=10+0|ka=11+1221|pa=12+963|i.ns_cecak.ns=12@-170,10+0|uniA9C7=15+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9A9,U+A9BC,U+A981,U+A98F,U+A9B8,U+A9A4,U+A9B6,U+A9AB,U+A9BA,U+A981,U+200B,U+A9A8,U+A9B8,U+A9AE,U+A9A4,U+A9C8;[pa=0+963|ma=1+970|ae.ns_cecak.ns=1@-62,10+0|ka=4+1221|u.ns=4@-1,0+0|na=6+989|i.ns=6@-71,10+0|taling=8+677|ra=8+915|cecak.ns=8@-321,10+0|space=11+0|bha=12+879|u.ns=12@-37,0+0|wa=14+967|na=15+989|uniA9C8=16+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A981,U+A98F,U+A9BE,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+A9C8;[ma=0+970|cecak.ns=0@-321,10+0|ka=2+1221|pengkal=2+376|space=4+0|ha=5+1195|i.ns_cecak.ns=5@-182,10+0|space=8+0|nga=9+976|ya=10+1383|u.ns=10@-1,0+0|gha=12+1258|pengkal=12+376|ka=14+1221|layar.ns=14@-250,10+0|tha=16+967|uniA9C8=17+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9A4,U+A9C0,U+A9A7,U+A981,U+A98F,U+A9B6,U+A9A0,U+A9C0,U+A9B2,U+A994,U+A9B8,U+A995,U+A9A5,U+A9C0,U+A9A5,U+A9BC,U+A9A4,U+A9C8;[ta=0+1183|na=1+989|ba.pas=1+0|cecak.ns=1@-330,10+0|ka=5+1221|i.ns=5@-42,10+0|ta=7+1183|ha.pas=7+1090|nga=10+976|u.ns=10+0|ca=12+1043|pa=13+963|pa.pas=13+830|ae.ns=13@52,10+0|na=17+989|uniA9C8=18+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+200B,U+A988,U+A9A4,U+A9C0,U+200B,U+A995,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9BA,U+A9B4,U+A98F,U+A9C0;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|space=5+0|ukara=6+976|na=7+989|pangkon=7+391|space=9+0|ca=10+1043|u.ns=10+0|na=12+989|pangkon=12+391|space=14+0|taling=15+677|ha=15+1195|tarung=15+413|ka=18+1221|pangkon=18+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0,U+A98F,U+A9BF,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9B2,U+A997,U+A9B6,U+A9C8;[ha=0+1195|da=1+1063|i.ns=1@-11,10+0|na=3+989|i.ns_cecak.ns=3@-182,10+0|nga_cakra=6+1221|ka.pas_cakra=8+253|ta=8+1183|taling=12+677|tha=12+967|tarung=12+413|na=15+989|ha.pas=15+1090|ja=18+991|i.ns=18@-24,10+0|uniA9C8=20+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A994,U+A9BF,U+A9BA,U+A983,U+A9B2,U+A9B6,U+A981,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0;[pa=0+963|taling=1+677|nga_cakra=1+1221|wignyan=1+353|ha=5+1195|i.ns_cecak.ns=5@-182,10+0|ma=8+970|sa=9+1088|ja.pas=9@200,0+0|i.ns=9@0,10+0|da=13+1063|sa.pas=13+830|la=16+1194|i.ns=16@-70,10+0|ka=18+1221|i.ns=18@-42,10+0|na=20+989|pangkon=20+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A0,U+A9BD,U+A9A9,U+A9C0,U+A9A5,U+A9BF,U+A9A2,U+A9B1,U+A9B6,U+A983,U+200B,U+A992,U+A9BC,U+A981,U+A9B2,U+A9AD,U+A9B6,U+A9A0,U+A9C0;[ta=0+1183|ae.ns=0@-44,10+0|na=2+989|ta.pas.alt=2+0|keret.ns.alt=2+0|ma=6+970|pa.pas_cakra=6+1074|da=10+1063|sa=11+1088|i.ns=11@0,10+0|wignyan=11+353|space=14+0|ga=15+938|ae.ns_cecak.ns=15@9,10+0|ha=18+1195|la=19+1194|i.ns=19@-70,10+0|ta=21+1183|pangkon=21+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B2,U+A981,U+A992,U+A9AB,U+A9A5,U+A9C0,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+200B,U+A9AF,U+A9B8,U+A9B0,U+A9BA,U+A997;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ka=3+1221|cecak.ns=3@-301,10+0|space=5+0|ha=6+1195|cecak.ns=6@-330,10+0|ga=8+938|ra=9+915|pa=10+963|pangkon=10+391|space=12+0|ra=13+915|taling=14+677|da=14+1063|na=16+989|pangkon=16+391|space=18+0|sha=19+938|u.ns=19+0|taling=21+677|ssa=21+1012|ja=23+991]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9B2,U+A997,U+A9B6,U+A9A9,U+A9B3,U+A9B8,U+A983,U+A98F,U+A9B3,U+A9A9,U+A9B3,U+A9A2,U+A9C0,U+200C,U+A994,U+A9A2,U+A9C0,U+A9A4,U+A9A4,U+A9C0;[ra=0+915|taling=1+677|da=1+1063|na=3+989|ha.pas=3+1090|ja=6+991|i.ns=6@-24,10+0|ma=8+970|cecaktelu.ns=8@-126,10+0|u.ns=8@-1,0+0|wignyan=8+353|ka=12+1221|cecaktelu.ns=12@-252,10+0|ma=14+970|cecaktelu.ns=14@-126,10+0|da=16+1063|pangkon=16+391|space=18+0|nga=19+976|da=20+1063|na.pas=20@-1,0+0|na=23+989|pangkon=23+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9B8,U+A9AD,U+A9A4,U+A9C0,U+A997,U+A9B8,U+A9A9,U+A9A2,U+A9B6,U+A9AD,U+A9AE,U+A9AD,U+A9C0,U+A9A0,U+A9B2,U+A9B8,U+A9A4,U+A9C0,U+A997,U+A9B6,U+A9A9,U+A9C0,U+A9A9,U+A9AE,U+A9AD,U+A9C0;[wa=0+967|u.ns=0@-1,0+0|la=2+1194|na=3+989|ja.pas.alt=3+0|u.ns.pas=3+0|ma=7+970|da=8+1063|i.ns=8@-11,10+0|la=10+1194|wa=11+967|la=12+1194|ta.pas=12+0|ha=15+1317|u.ns=15@-123,0+0|na=17+989|ja.pas=17@200,0+0|i.ns=17@-71,10+0|ma=21+970|ma.pas=21@-1,0+0|wa=24+967|la=25+1194|pangkon=25+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A991,U+A9AD,U+A9B6,U+A9A6,U+A9A1,U+A9B8,U+A9AD,U+A9C0,U+A9AD,U+A983,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981;[kha=0+1289|la=1+1194|i.ns=1@-70,10+0|pha=3+1027|tha=4+967|u.ns=4@-1,0+0|la=6+1194|la.pas=6@-278,0+0|wignyan=6+353|space=10+0|ha=11+1195|i.ns_cecak.ns=11@-182,10+0|ka=14+1221|cecak.ns=14@-301,10+0|space=16+0|ja=17+991|u.ns=17@-4,0+0|ma=19+970|ae.ns=19@-59,10+0|na=21+989|ae.ns_cecak.ns=21@-71,10+0|space=24+0|ka=25+1221|pa=26+963|i.ns_cecak.ns=26@-170,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9A4,U+A9C0,U+A99D,U+A9B6,U+A981,U+A994,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9C8;[ta=0+1183|na=1+989|dda.pas=1+0|i.ns_cecak.ns=1@-182,10+0|nga=6+976|na=7+989|na.pas=7+0|i.ns=7@-71,10+0|pa=11+963|u.ns=11+0|na=13+989|sa.pas=13+830|wa=16+967|u.ns=16@-1,0+0|cecak.ns=16@-320,10+0|space=19+0|ba=20+1207|la=21+1194|ba.pas=21+0|la=24+1194|la.pas=24@-278,0+0|na=27+989|pangkon=27+391|uniA9C8=29+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B6,U+A9A4,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9A5,U+A9BA,U+A994,U+A9BC,U+A9A0,U+A9C0,U+A9A0,U+A9A4,U+A9C0,U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A99F,U+A9A1,U+A9C8;[ma=0+970|i.ns=0@-62,10+0|taling=2+677|na=2+989|cecak.ns=2@-330,10+0|tarung=2+413|ka=6+1221|space=7+0|taling=8+677|pa=8+963|nga=10+976|ae.ns=10@-63,10+0|ta=12+1344|ta.pas=12@-162,0+0|na=15+989|ja.pas.alt=15+0|u.ns.pas=15+0|ma=19+970|ae.ns=19@-59,10+0|na=21+989|ae.ns_cecak.ns=21@-71,10+0|space=24+0|da=25+1063|ngalelet=26+1294|ma=27+970|nna.pas=27@-1,0+0|tha=30+967|uniA9C8=31+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A98F,U+A991,U+A992,U+A993,U+A994,U+A995,U+A996,U+A997,U+A999,U+A99A,U+A99B,U+A99C,U+A99D,U+A99E,U+A99F,U+A9A0,U+A9A1,U+A9A2,U+A9A3,U+A9A4,U+A9A5,U+A9A6,U+A9A7,U+A9A8,U+A9A9,U+A9AA,U+A9AB,U+A9AD,U+A9AE,U+A9AF,U+A9B0,U+A9B1,U+A9B2;[ka=0+1221|kha=1+1289|ga=2+938|gha=3+1258|nga=4+976|ca=5+1043|cha=6+1479|ja=7+991|jha=8+1159|nya=9+1439|tta=10+976|ttha=11+976|dda=12+1071|ddha=13+841|nna=14+1198|ta=15+1183|tha=16+967|da=17+1063|dha=18+1027|na=19+989|pa=20+963|pha=21+1027|ba=22+1207|bha=23+879|ma=24+970|ya=25+1383|ra=26+915|la=27+1194|wa=28+967|sha=29+938|ssa=30+1012|sa=31+1088|ha=32+1195]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A4,U+A9C0,U+A9A0,U+A9BA,U+A9A4,U+A9C0,U+A9A1,U+A9B8,U+A9A9,U+A9BC,U+A981,U+A992,U+A9B8,U+A981,U+200B,U+A9A6,U+A9BF,U+A9AE,U+A9B6,U+A9AB,U+A9A2,U+A9B6,U+A982,U+A997,U+A9C9;[taling=0+677|da=0+1063|na=2+989|na.pas=2+0|i.ns_cecak.ns=2@-182,10+0|space=7+0|ra=8+915|taling=9+677|da=9+1063|na=11+989|nga.pas=11+0|taling=14+677|na=14+989|ta.pas=14+0|na=18+989|tha.pas.alt=18+0|u.ns.pas=18@225,0+0|ma=22+970|ae.ns_cecak.ns=22@-62,10+0|ga=25+1060|u.ns=25@-122,0+0|cecak.ns=25@-372,10+0|space=28+0|pha_cakra=29+1318|wa=31+967|i.ns=31@-61,10+0|ra=33+915|da=34+1063|i.ns_layar.ns=34@-122,10+0|ja=37+991|uniA9C9=38+687]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A9A9,U+A9A1,U+A9AB,U+A9A9,U+A9C0,U+A9A2,U+A9B8,U+A98F,U+A9C0,U+A9AB,U+A9B8,U+A9A9,U+A9B8,U+A9B2,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9A0,U+A9BC,U+A98A,U+A981,U+A994,U+A9B6,U+A981,U+200B,U+A98F,U+A9AB,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A997,U+A9AE,U+A9B6,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ma=3+970|tha=4+967|ra=5+915|ma=6+970|da.pas_u.ns=6@-1,0+0|ka=10+1221|ra.pas=10@-1,0+0|u.ns.pas=10@-1,0+0|ma=14+970|u.ns=14@-1,0+0|ha=16+1195|u.ns=16@-1,0+0|na=18+989|pangkon=18+391|space=20+0|ta=21+1183|ae.ns=21@-44,10+0|ngalelet=23+977|cecak.ns=23@-324,10+0|nga=25+976|i.ns_cecak.ns=25@-177,10+0|space=28+0|ka=29+1221|ra=30+915|taling=31+677|tha=31+967|tarung=31+413|na=34+989|ja.pas=34@200,0+0|wa=37+967|i.ns=37@-61,10+0|uniA9C8=39+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9BC,U+A99D,U+A9B6,U+200B,U+A992,U+A9A9,U+A9C0,U+A9A5,U+A9B6,U+A981,U+200B,U+A98F,U+A997,U+A9BC,U+A981,U+200B,U+A9AD,U+A9A4,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+A9B1,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+A9B1,U+A9C0,U+A9B1,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B;[wa=0+967|ae.ns=0@-58,10+0|dda=2+1071|i.ns=2@9,10+0|space=4+0|ga=5+938|ma=6+970|pa.pas=6+830|i.ns_cecak.ns=6@-62,10+0|space=11+0|ka=12+1221|ja=13+991|ae.ns_cecak.ns=13@-24,10+0|space=16+0|la=17+1194|na=18+989|sa.pas=18+830|taling=21+677|na=21+989|na.pas=21+0|sa=25+1088|sa.pas=25+830|taling=28+677|na=28+989|na.pas=28+0|sa=32+1088|sa.pas=32+830|i.ns=32@49,10+0|pa=36+963|u.ns=36+0|na=38+989|pangkon=38+391|space=40+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9B1,U+A9AB,U+A9AE,U+A9BA,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A9AB,U+A9A0,U+A9C0,U+200B,U+A9A2,U+A9BA,U+A9AB,U+A9A4,U+A9BF,U+A9B8,U+A9B1,U+A9C0,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B8,U+A997,U+A9C0,U+A9AE,U+A9AD,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+A9C8;[taling=0+677|ma=0+970|cecak.ns=0@-321,10+0|tarung=0+413|ka=4+1221|space=5+0|sa=6+1088|ra=7+915|taling=8+677|wa=8+967|da=10+1063|i.ns=10@-11,10+0|na=12+989|i.ns_cecak.ns=12@-182,10+0|ra=15+915|ta=16+1183|pangkon=16+391|space=18+0|taling=19+677|da=19+1063|ra=21+915|na_cakra_u.ns=22+1343|sa=25+1088|ka.pas=25+0|ae.ns=25@3,10+0|na=29+989|ha.pas=29+1090|u.ns=29+0|ja_wa.pas=33+987|la=36+1194|na=37+989|na.pas=37+0|i.ns_cecak.ns=37@-182,10+0|uniA9C8=42+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B6,U+A9A4,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9AE,U+A98F,U+A9B6,U+A9AD,U+A9C0,U+A9AA,U+A9AA,U+A9B1,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9C0,U+A9AD,U+A9BA,U+A9B4,U+A9B2,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9BC,U+200B,U+A992,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9BA,U+A9A4,U+A98F,U+A9B6,U+A9B2,U+A9A4,U+A9C0,U+A9C7;[ma=0+970|i.ns=0@-62,10+0|taling=2+677|na=2+989|cecak.ns=2@-330,10+0|tarung=2+413|ka=6+1221|space=7+0|wa=8+967|ka=9+1221|i.ns=9@-42,10+0|la=11+1194|ya.pas=11+0|ya=14+1383|sa=15+1088|na=16+989|ka.pas=16+0|taling=19+677|la=19+1194|la.pas=19@-278,0+0|tarung=19+413|ha=24+1195|u.ns=24@-1,0+0|sa=26+1088|ta.pas=26+0|ae.ns=26@3,10+0|space=30+0|ga=31+938|u.ns=31+0|taling=33+677|la=33+1194|ba.pas=33+0|na=37+989|ka=38+1221|i.ns=38@-42,10+0|ha=40+1195|na=41+989|pangkon=41+391|uniA9C7=43+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9B6,U+A9A4,U+A9BD,U+A9A4,U+A983,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9A9,U+A981,U+A992,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A9A5,U+A9A5,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A5,U+A98F,U+A9BA,U+A9B4,U+A9AD,U+A9B6,U+A983,U+A9C8;[pa=0+963|i.ns=0@-59,10+0|na=2+989|keret.ns=2+0|na=4+989|wignyan=4+353|ka=6+1221|ae.ns=6@-39,10+0|na=8+989|ma.pas=8+0|cecak.ns=8@-330,10+0|taling=12+677|ga=12+938|na=14+989|na.pas=14+0|i.ns=14@-71,10+0|pa=18+963|u.ns=18+0|na=20+989|pangkon=20+391|space=22+0|ha=23+1195|i.ns_cecak.ns=23@-182,10+0|space=26+0|pa=27+963|pa=28+963|na=29+989|ha.pas=29+1090|i.ns_cecak.ns=29@-71,10+0|ka=34+1221|cecak.ns=34@-301,10+0|space=36+0|pa=37+963|taling=38+677|ka=38+1221|tarung=38+413|la=41+1194|i.ns=41@-70,10+0|wignyan=41+353|uniA9C8=44+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9A9,U+A9B8,U+A997,U+A9C0,U+A9AE,U+A9BA,U+A981,U+200B,U+A98A,U+A989,U+A9B1,U+A9C0,U+A9A4,U+A9BC,U+A982,U+A9AB,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B1,U+A9B8,U+A9B1,U+A9A0,U+A9BE,U+200B,U+A9A0,U+A9BC,U+A9A9,U+A9BC,U+A9A4,U+A9C0,U+A9A4,U+A9B8,U+A9B2,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9C8;[ta=0+1183|u.ns=0@-1,0+0|ma=2+970|u.ns=2@-1,0+0|taling=4+677|ja_wa.pas=4+987|cecak.ns=4@-230,10+0|space=9+0|ngalelet=10+977|pacerek=11+963|sa=12+1088|na.pas=12+0|ae.ns_layar.ns=12@-59,10+0|ra=17+915|i.ns=17@-62,10+0|pa=19+963|u.ns=19+0|na=21+989|pangkon=21+391|space=23+0|sa=24+1088|u.ns=24+0|sa=26+1088|ta=27+1183|pengkal=27+376|space=29+0|ta=30+1183|ae.ns=30@-44,10+0|ma=32+970|ae.ns=32@-59,10+0|na=34+989|na.pas.alt=34+0|u.ns.pas=34@166,0+0|taling=38+677|ha=38+1195|tarung=38+413|na=41+989|na.pas=41+0|i.ns=41@-71,10+0|uniA9C8=45+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B2,U+A994,U+A9BD,U+A981,U+A992,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+200B,U+A991,U+A9AB,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+200B,U+A9B2,U+A9A2,U+A9B6,U+A99F,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ka=3+1221|cecak.ns=3@-301,10+0|space=5+0|ha=6+1195|nga=7+976|keret.ns=7+0|cecak.ns=7@-325,10+0|ga=10+938|na=11+989|na.pas=11+0|i.ns=11@-71,10+0|space=15+0|kha=16+1289|ra=17+915|taling=18+677|tha=18+967|tarung=18+413|na=21+989|da.pas=21+0|ngalelet=24+977|ma=25+970|ha.pas=25+1090|i.ns_cecak.ns=25@-71,10+0|space=30+0|nga=31+976|ya=32+1383|u.ns=32@-1,0+0|gha=34+1258|pengkal=34+376|ka=36+1221|layar.ns=36@-250,10+0|tha=38+967|space=39+0|ha=40+1195|da=41+1063|i.ns=41@-11,10+0|nna=43+1198|i.ns_cecak.ns=43@-137,10+0|nga_cakra=46+1221|ta=48+1183|pangkon=48+391|uniA9C8=50+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A99F,U+A9A1,U+200B,U+A9B2,U+A9A9,U+A989,U+A981,U+A994,U+A9B6,U+200B,U+A9A2,U+A9B6,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9B1,U+A9BC,U+A9A4,U+A9BA,U+A9A4,U+A9C0,U+A9A5,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+200B,U+A9A0,U+A981,U+A992,U+A9AD,U+A9C0,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ja=0+991|u.ns=0@-4,0+0|ma=2+970|ae.ns=2@-59,10+0|na=4+989|ae.ns_cecak.ns=4@-71,10+0|space=7+0|da=8+1063|ngalelet=9+1294|ma=10+970|nna.pas=10@-1,0+0|tha=13+967|space=14+0|ha=15+1195|ma=16+970|pacerek=17+963|cecak.ns=17@-318,10+0|nga=19+976|i.ns=19@-66,10+0|space=21+0|da=22+1063|i.ns=22@-11,10+0|na=24+989|ta.pas=24+0|ae.ns=24@-68,10+0|na=28+989|sa.pas=28+830|ae.ns=28@52,10+0|taling=32+677|na=32+989|taling=34+677|na=34+989|pa.pas=34+830|tarung=34+413|na=39+989|pangkon=39+391|space=41+0|ta=42+1183|cecak.ns=42@-306,10+0|ga=44+938|la=45+1194|ka.pas=45+0|pa=48+963|i.ns_cecak.ns=48@-170,10+0|uniA9C7=51+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9CB,U+A9B1,U+A9A7,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B8,U+A9AE,U+A9BA,U+A9B4,U+A981,U+A98F,U+A9AD,U+A9B2,U+A9B6,U+A9AB,U+A98F,U+A9BA,U+A98F,U+A9A4,U+A9C0,U+A99B,U+A9B6,U+A9A9,U+A982,U+A9A2,U+A9B6,U+A98F,U+A9AD,U+A9A4,U+A9C0,U+A9A2,U+A982,U+A9A7,U+A9BA,U+A9A9,U+A982,U+A9A0,U+A9A7,U+A9A0,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9B2,U+A98F,U+A9C0,U+A9B2,U+A98F,U+A9C0,U+A98F,U+A981,U+A9A5,U+A99D,U+A9C9;[uniA9CB=0+439|sa=1+1088|ba=2+1207|ae.ns=2@-13,10+0|na=4+989|ha.pas=4+1090|u.ns=4+0|taling=8+677|wa=8+967|cecak.ns=8@-320,10+0|tarung=8+413|ka=12+1221|la=13+1194|ha=14+1195|i.ns=14@-71,10+0|ra=16+915|taling=17+677|ka=17+1221|ka=19+1221|na=20+989|tta.pas=20+0|i.ns=20@-71,10+0|ma=24+970|layar.ns=24@-270,10+0|da=26+1063|i.ns=26@-11,10+0|ka=28+1221|la=29+1194|na=30+989|da.pas=30+0|layar.ns=30@-279,10+0|taling=34+677|ba=34+1207|ma=36+970|layar.ns=36@-270,10+0|ta=38+1183|ba=39+1207|ta=40+1183|la.pas=40@-273,0+0|na=43+989|ha.pas=43+1090|ka=46+1221|ha.pas=46+1090|ka=49+1221|ka.pas=49@-1,0+0|cecak.ns=49@-301,10+0|pa=53+963|dda=54+1071|uniA9C9=55+687]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A981,U+A98F,U+A9B6,U+A981,U+200B,U+A9A5,U+A9AB,U+200B,U+A9A7,U+A9BA,U+A9B4,U+A981,U+A9B1,U+200B,U+A9A1,U+A9BE,U+A9BA,U+A9B4,U+A981,U+A9B2,U+A9C0,U+A9AE,U+200B,U+A992,U+A9BA,U+A9B4,U+A9AD,U+A9BA,U+A9B4,U+A981,U+A994,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+200B,U+A9B2,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0;[sa=0+1088|cecak.ns=0@-259,10+0|ka=2+1221|i.ns_cecak.ns=2@-153,10+0|space=5+0|pa=6+963|ra=7+915|space=8+0|taling=9+677|ba=9+1207|cecak.ns=9@-275,10+0|tarung=9+413|sa=13+1088|space=14+0|taling=15+677|tha=15+967|pengkal=15+376|cecak.ns=15+0|tarung=15+413|ha=20+1195|wa.pas=20@-1,0+0|space=23+0|taling=24+677|ga=24+938|tarung=24+413|taling=27+677|la=27+1194|cecak.ns=27@-329,10+0|tarung=27+413|nga=31+976|na=32+989|ha.pas=32+1090|i.ns_cecak.ns=32@-71,10+0|space=37+0|nga=38+976|ya=39+1383|u.ns=39@-1,0+0|gha=41+1258|pengkal=41+376|ka=43+1221|layar.ns=43@-250,10+0|tha=45+967|space=46+0|ha=47+1195|da=48+1063|i.ns=48@-11,10+0|na=50+989|i.ns_cecak.ns=50@-182,10+0|nga_cakra=53+1221|ta=55+1183|pangkon=55+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A994,U+A982,U+A9B0,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+200B,U+A9AF,U+A9A9,U+A9C0,U+A9A6,U+A9BA,U+A9AA,U+A9A4,U+A9C0,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+200B,U+A9B2,U+A9B6,U+A981,U+A991,U+A981,U+200B,U+A9AF,U+A9B6,U+A99F,U+A9B8,U+A9AE,U+A9B8,U+A9A4,U+A9C0,U+A98F,U+A997,U+A9BC,U+A981,U+200B,U+A9AF,U+A9B8,U+A9AD,U+A9C0,U+A9A1,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9A9,U+A9BC,U+A981,U+A991,U+A9B8,U+A9A8,U+A9B8,U+A9AE,U+A99F,U+A9C8;[nga=0+976|layar.ns=0@-274,10+0|ssa=2+1012|space=3+0|da=4+1063|ngalelet=5+977|ma=6+970|pangkon=6+391|space=8+0|sha=9+938|taling=10+677|ma=10+970|pha.pas=10+1054|ya=14+1383|na=15+989|da.pas=15+0|ngalelet=18+977|ma=19+970|pangkon=19+391|space=21+0|ha=22+1195|i.ns_cecak.ns=22@-182,10+0|kha=25+1289|cecak.ns=25@-359,10+0|space=27+0|sha=28+938|i.ns=28@8,10+0|nna=30+1198|u.ns=30+0|wa=32+1126|u.ns=32@-160,0+0|na=34+989|ka.pas=34+0|ja=37+991|ae.ns_cecak.ns=37@-24,10+0|space=40+0|sha=41+938|u.ns=41+0|la=43+1194|tha.pas=43+0|na=46+989|pangkon=46+391|space=48+0|ha=49+1195|ma=50+970|ae.ns_cecak.ns=50@-62,10+0|kha=53+1289|u.ns=53@-300,0+0|bha=55+879|u.ns=55@-37,0+0|wa=57+967|nna=58+1198|uniA9C8=59+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9A2,U+A9BC,U+A992,U+A9C0,U+A992,U+A9B6,U+A981,U+200B,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0,U+200B,U+A9AA,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A4,U+A9C0,U+A9A0,U+A9BA,U+A9A4,U+A9C0,U+A9A1,U+A9B8,U+A9A9,U+A9BC,U+A981,U+A992,U+A9B8,U+A981,U+200B,U+A9A6,U+A9BF,U+A9AE,U+A9B6,U+A9AB,U+A9A2,U+A9B6,U+A982,U+A997,U+A9C8;[ha=0+1195|da=1+1063|ae.ns=1@-8,10+0|ga=3+938|ga.pas=3+0|i.ns_cecak.ns=3@-102,10+0|space=8+0|ma=9+970|sa=10+1088|ja.pas=10@200,0+0|i.ns=10@0,10+0|da=14+1063|sa.pas=14+830|la=17+1194|i.ns=17@-70,10+0|ka=19+1221|i.ns=19@-42,10+0|na=21+989|pangkon=21+391|space=23+0|ya=24+1383|sa=25+1088|na=26+989|na.pas=26+0|i.ns=26@-71,10+0|pa=30+1085|u.ns=30@-122,0+0|na=32+989|ra.pas=32+0|taling=35+677|da=35+1063|na=37+989|nga.pas=37+0|taling=40+677|na=40+989|ta.pas=40+0|na=44+989|tha.pas.alt=44+0|u.ns.pas=44@225,0+0|ma=48+970|ae.ns_cecak.ns=48@-62,10+0|ga=51+1060|u.ns=51@-122,0+0|cecak.ns=51@-372,10+0|space=54+0|pha_cakra=55+1318|wa=57+967|i.ns=57@-61,10+0|ra=59+915|da=60+1063|i.ns_layar.ns=60@-122,10+0|ja=63+991|uniA9C8=64+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A992,U+A9B8,U+A9A7,U+A9BC,U+A982,U+A9A4,U+A9B8,U+A982,U+200B,U+A99D,U+A983,U+A9B2,U+A9BA,U+A9AB,U+A983,U+200B,U+A986,U+A9B1,U+A9C0,U+A9A0,U+A9B6,U+A9A9,U+A9BA,U+A9AE,U+A983,U+200B,U+A9AA,U+A9BA,U+A9B4,U+A992,U+A9BE,U+A98F,U+A982,U+A9A0,U+200B,U+A9A0,U+A9B8,U+A9AE,U+A9B6,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A9,U+A9B6,U+A9A4,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+200B,U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+A9AA,U+A9BA,U+A9B4,U+A9B1,U+A9BA,U+200B,U+A9A7,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A995,U+A9BA,U+A9B4,U+A9C8;[ga=0+938|u.ns=0+0|ba=2+1207|ae.ns_layar.ns=2@-75,10+0|na=5+989|u.ns=5+0|layar.ns=5@-279,10+0|space=8+0|dda=9+1071|wignyan=9+353|taling=11+677|ha=11+1195|ra=13+915|wignyan=13+353|space=15+0|ikara=16+1207|sa=17+1088|ta.pas=17+0|i.ns=17@0,10+0|taling=21+677|ma=21+970|wa=23+967|wignyan=23+353|space=25+0|taling=26+677|ya=26+1383|tarung=26+413|ga=29+938|pengkal=29+376|ka=31+1221|layar.ns=31@-250,10+0|ta=33+1183|space=34+0|ta=35+1183|u.ns=35@-1,0+0|wa=37+967|i.ns=37@-61,10+0|na=39+989|ha.pas=39+1090|i.ns_cecak.ns=39@-71,10+0|ka=44+1221|cecak.ns=44@-301,10+0|space=46+0|ma=47+970|i.ns=47@-62,10+0|na=49+1148|u.ns=49@-159,0+0|la=51+1194|ya.pas=51+0|space=54+0|ta=55+1183|u.ns=55@-1,0+0|wa=57+967|taling=58+838|na=58+989|ya.pas=58+0|tarung=58+413|taling=63+677|sa=63+1088|space=65+0|ba=66+1207|la.pas=66@-270,0+0|taling=69+838|na=69+989|ca.pas=69+0|tarung=69+413|uniA9C8=74+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A992,U+A9B6,U+A983,U+200B,U+A9A5,U+A9B8,U+A9A4,U+A9B6,U+A98F,U+200B,U+A9A7,U+A9A7,U+A9C0,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9A0,U+A9A4,U+A983,U+200B,U+A994,U+A9BF,U+A9B6,U+A98F,U+A9B6,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B1,U+A9A9,U+A9B6,U+200B,U+A994,U+A9C0,U+A9AD,U+A9B8,U+A9AB,U+A9B8,U+A992,U+A9C0,U+A99D,U+A9A0,U+A9BC,U+A981,U+200B,U+A98C,U+A9AB,U+A9BA,U+A9B4,U+A9A6,U+A983,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ga=3+938|i.ns=3@9,10+0|wignyan=3+353|space=6+0|pa=7+963|u.ns=7+0|na=9+989|i.ns=9@-71,10+0|ka=11+1221|space=12+0|ba=13+1207|taling=14+677|ba=14+1207|wa.pas=14+0|tarung=14+413|na=19+989|ta.pas=19+0|ae.ns=19@-68,10+0|na=23+989|na.pas=23+0|i.ns=23@-71,10+0|pa=27+963|u.ns=27+0|na=29+989|sa.pas=29+830|wa=32+967|u.ns=32@-1,0+0|cecak.ns=32@-320,10+0|space=35+0|ba=36+1207|la=37+1194|ba.pas=37+0|la=40+1194|la.pas=40@-278,0+0|na=43+989|ta.pas=43+0|na=46+989|wignyan=46+490|space=48+0|nga_cakra=49+1221|i.ns=49@-18,10+0|ka=52+1221|i.ns=52@-42,10+0|space=54+0|ha=55+1195|i.ns_cecak.ns=55@-182,10+0|ka=58+1221|cecak.ns=58@-301,10+0|space=60+0|sa=61+1088|ma=62+970|i.ns=62@-62,10+0|space=64+0|nga=65+976|la.pas.alt=65+0|u.ns.pas=65+0|ra=69+1049|u.ns=69@-134,0+0|ga=71+938|dda.pas=71+0|ta=74+1183|ae.ns_cecak.ns=74@-47,10+0|space=77+0|ekara=78+781|taling=79+677|ra=79+915|tarung=79+413|pha=82+1027|wignyan=82+353|uniA9C8=84+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A9BA,U+A9B4,U+A98F,U+A9BA,U+A9B4,U+A981,U+A994,U+A9A4,U+A9C0,U+A9B1,U+A98F,U+A9B6,U+A981,U+200B,U+A9A5,U+A9AB,U+200B,U+A9A9,U+A9B8,U+A9B1,U+A9C0,U+A9AD,U+A9B6,U+A9A9,U+A9B6,U+A9A4,U+A9C0,U+200B,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A994,U+A9BF,U+A99A,U+A9C0,U+A995,U+A981,U+200B,U+A9B1,U+A9B2,U+200B,U+A994,U+A9AE,U+A9A0,U+A9C0,U+A9B2,U+A9AE,U+A9A0,U+A9C0,U+A9A0,U+A9B6,U+200B,U+A9A5,U+A981,U+A992,U+A9AB,U+A9A5,U+A9C0,U+A9A5,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A7,U+A9BA,U+A9B2,U+A9B6,U+200B,U+A995,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A2,U+A9BF,U+A9A2,U+A9B6,U+A9A5,U+A9BF,U+A997,U+A9C8;[taling=0+677|sa=0+1088|tarung=0+413|taling=3+677|ka=3+1221|cecak.ns=3@-301,10+0|tarung=3+413|nga=7+976|na=8+989|sa.pas=8+830|ka=11+1221|i.ns_cecak.ns=11@-153,10+0|space=14+0|pa=15+963|ra=16+915|space=17+0|ma=18+970|u.ns=18@-1,0+0|sa=20+1088|la.pas=20@-225,0+0|i.ns=20@0,10+0|ma=24+970|i.ns=24@-62,10+0|na=26+989|pangkon=26+391|space=28+0|taling=29+677|da=29+1063|taling=31+677|na=31+989|na.pas=31+0|space=35+0|ha=36+1195|i.ns_cecak.ns=36@-182,10+0|ka=39+1221|cecak.ns=39@-301,10+0|space=41+0|nga_cakra=42+1221|nya=44+1439|ca.pas=44@-1,0+0|cecak.ns=44@-361,10+0|space=48+0|sa=49+1088|ha=50+1195|space=51+0|nga=52+976|wa=53+967|ta=54+1183|ha.pas=54+1090|wa=57+967|ta=58+1183|ta.pas=58@-1,0+0|i.ns=58@-47,10+0|space=62+0|pa=63+963|cecak.ns=63@-318,10+0|ga=65+938|ra=66+915|pa=67+963|pa.pas=67+830|i.ns=67@49,10+0|pa=71+963|u.ns=71+0|na=73+989|ma.pas=73+0|sa=76+1088|ja.pas=76@200,0+0|i.ns=76@0,10+0|da=80+1063|pangkon=80+391|space=82+0|ra=83+915|taling=84+677|da=84+1063|na=86+989|nga.pas=86+0|taling=89+677|ba=89+1207|ha=91+1195|i.ns=91@-71,10+0|space=93+0|taling=94+677|ca=94+1043|tarung=94+413|da.pas_cakra=97+238|na=97+989|da=101+1063|i.ns=101@-11,10+0|pa_cakra=103+1221|ja=105+991|uniA9C8=106+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AD,U+A997,U+A9BC,U+A981,U+200B,U+A98F,U+A9AE,U+A98F,U+A9A5,U+A9C0,U+A9A5,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A981,U+A992,U+A9BA,U+200B,U+A9A5,U+A982,U+A9AD,U+A9B8,U+A9A4,U+A9B6,U+A981,U+200B,U+A986,U+A9B1,U+A9C0,U+A9AD,U+A9A9,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9A9,U+A9B8,U+A9B1,U+A9C0,U+A9AD,U+A9B6,U+A9A9,U+A9B6,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9B1,U+A9AD,U+A9A9,U+A9B6,U+A9AD,U+A9A9,U+A9B6,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9A5,U+A9A9,U+A9C0,U+A9A7,U+A9B6,U+A98F,U+A98F,U+A9C0,U+A98F,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9A2,U+A9B6,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9BC,U+A9A9,U+A9B6,U+A9B1,U+A9C0,U+A98F,U+A9AD,U+A9B6,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A981,U+A992,U+A9AD,U+A9C0,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[la=0+1194|ja=1+991|ae.ns_cecak.ns=1@-24,10+0|space=4+0|ka=5+1221|wa=6+967|ka=7+1221|pa=8+963|pa.pas=8+830|ka=11+1221|ae.ns=11@-39,10+0|na=13+989|ka.pas=13+0|cecak.ns=13@-330,10+0|taling=17+677|ga=17+938|space=19+0|pa=20+963|layar.ns=20@-267,10+0|la=22+1194|u.ns=22+0|na=24+989|i.ns_cecak.ns=24@-182,10+0|space=27+0|ikara=28+1207|sa=29+1088|la.pas=29@-225,0+0|ma=32+970|la.pas=32@-167,0+0|na=35+989|ma.pas.alt=35+0|u.ns.pas=35+0|sa=39+1088|la.pas=39@-225,0+0|i.ns=39@0,10+0|ma=43+970|i.ns=43@-62,10+0|na=45+989|ha.pas=45+1090|i.ns_cecak.ns=45@-71,10+0|space=50+0|sa=51+1088|la=52+1194|ma=53+970|i.ns=53@-62,10+0|la=55+1194|ma=56+970|i.ns=56@-62,10+0|na=58+989|i.ns=58@-71,10+0|pa=60+963|u.ns=60+0|na=62+989|pangkon=62+391|space=64+0|pa=65+963|ma=66+970|ba.pas=66@-1,0+0|i.ns=66@-62,10+0|ka=70+1221|ka=71+1221|ka.pas=71@-1,0+0|i.ns=71@-42,10+0|pa=75+963|u.ns=75+0|na=77+989|ha.pas=77+1090|i.ns_cecak.ns=77@-71,10+0|space=82+0|da=83+1063|i.ns=83@-11,10+0|na=85+1150|ta.pas=85@-161,0+0|ae.ns=85@-229,10+0|na=89+989|ka.pas=89+0|ae.ns=89@-68,10+0|ma=93+970|i.ns=93@-62,10+0|sa=95+1088|ka.pas=95+0|la=98+1194|i.ns=98@-70,10+0|taling=100+677|wa=100+967|tarung=100+413|na=103+989|ta.pas=103+0|cecak.ns=103@-330,10+0|ga=107+938|la=108+1194|ka.pas=108+0|pa=111+963|i.ns_cecak.ns=111@-170,10+0|uniA9C7=114+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9BF,U+A9B6,U+A98F,U+A9B6,U+200B,U+A994,U+A9BC,U+A995,U+A9BF,U+A9A0,U+A9C0,U+A992,U+A9A9,U+A9C0,U+A9A7,U+A982,U+A9AB,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9AE,U+A9B2,U+A9B8,U+200B,U+A9A4,U+A9AD,U+A9B6,U+A98F,U+200B,U+A9A4,U+A9B8,U+A997,U+A9B8,U+200B,U+A9A0,U+A9A4,U+A9C0,U+A99D,U+A9B6,U+A981,U+A994,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9B6,U+A9AA,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9B1,U+A98F,U+A9B6,U+A981,U+200B,U+A9B2,U+A9BA,U+A9B4,U+A981,U+A993,U+A9AB,U+A9B6,U+A9AA,U+A9BC,U+200B,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9B2,U+A9AD,U+A9B8,U+A9A4,U+A9C0,U+A9B2,U+A9AD,U+A9B8,U+A9A4,U+A9C0,U+A9C7;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|space=3+0|nga_cakra=4+1221|i.ns=4@-18,10+0|ka=7+1221|i.ns=7@-42,10+0|space=9+0|nga=10+976|ae.ns=10@-63,10+0|ca_cakra=12+1318|ta=14+1183|ga.pas=14@-1,0+0|ma=17+970|ba.pas=17@-1,0+0|layar.ns=17@-270,10+0|ra=21+915|i.ns=21@-62,10+0|pa=23+963|u.ns=23+0|na=25+989|sa.pas=25+830|wa=28+967|u.ns=28@-1,0+0|cecak.ns=28@-320,10+0|space=31+0|sa=32+1088|wa=33+967|u.ns=33@-1,0+0|cecak.ns=33@-320,10+0|space=36+0|wa=37+967|ha=38+1195|u.ns=38@-1,0+0|space=40+0|na=41+989|la=42+1194|i.ns=42@-70,10+0|ka=44+1221|space=45+0|na=46+989|u.ns=46+0|ja=48+991|u.ns=48@-4,0+0|space=50+0|ta=51+1183|na=52+989|dda.pas=52+0|i.ns_cecak.ns=52@-182,10+0|nga=57+976|na=58+989|ka.pas=58+0|la=61+1194|i.ns=61@-70,10+0|ya=63+1383|na=64+989|sa.pas=64+830|wa=67+967|u.ns=67@-1,0+0|cecak.ns=67@-320,10+0|space=70+0|ba=71+1207|la=72+1194|ba.pas=72+0|la=75+1194|la.pas=75@-278,0+0|na=78+989|sa.pas=78+830|ka=81+1221|i.ns_cecak.ns=81@-153,10+0|space=84+0|taling=85+677|ha=85+1195|cecak.ns=85@-330,10+0|tarung=85+413|gha=89+1258|ra=90+915|i.ns=90@-62,10+0|ya=92+1383|ae.ns=92@-71,10+0|space=94+0|taling=95+677|wa=95+967|tarung=95+413|na=98+989|ta.pas=98+0|ae.ns=98@-68,10+0|na=102+989|ha.pas=102+1090|i.ns_cecak.ns=102@-71,10+0|space=107+0|ha=108+1195|la=109+1194|u.ns=109+0|na=111+989|ha.pas=111+1090|la=114+1194|u.ns=114+0|na=116+989|pangkon=116+391|uniA9C7=118+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A9A2,U+A9BA,U+A9AB,U+A9BA,U+A981,U+A994,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0,U+A98F,U+A992,U+A9AB,U+A9A5,U+A9C0,U+200B,U+A9B1,U+A9A9,U+A9C0,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A9,U+A9B2,U+A9B8,U+A997,U+A9B8,U+A9A2,U+A9C0,U+A9A5,U+A9A4,U+A9C0,U+A99D,U+A9BC,U+A9A9,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+200B,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+200B,U+A9AF,U+A9B8,U+A9AB,U+A9A9,U+A9C0,U+A9A7,U+A9B6,U+200B,U+A9B1,U+A9B2,U+200B,U+A9A5,U+A9AD,U+A9A9,U+A9C0,U+A9A5,U+A983,U+A9B2,U+A9A4,U+A9C0,U+200B,U+A9B1,U+A982,U+A9A0,U+200B,U+A9A7,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A99D,U+A9B1,U+A9AE,U+A9A0,U+A9AE,U+A9B6,U+A9B1,U+A9C0,U+200B,U+A98F,U+A9A2,U+A9BA,U+A9B4,U+A9B1,U+A9C0,U+A9A0,U+A9C7;[sa=0+1088|taling=1+677|da=1+1063|taling=3+677|ra=3+915|cecak.ns=3@-321,10+0|nga=6+976|i.ns=6@-66,10+0|pa=8+963|u.ns=8+0|na=10+989|ma.pas=10+0|sa=13+1088|ja.pas=13@200,0+0|i.ns=13@0,10+0|da=17+1063|sa.pas=17+830|la=20+1194|i.ns=20@-70,10+0|ka=22+1221|i.ns=22@-42,10+0|na=24+989|ka.pas=24+0|ga=27+938|ra=28+915|pa=29+963|pangkon=29+391|space=31+0|sa=32+1088|ma=33+970|pa.pas=33+830|u.ns=33+0|taling=37+677|na=37+989|wa.pas=37+0|tarung=37+413|na=42+989|ta.pas=42+0|ae.ns=42@-68,10+0|na=46+989|ma.pas=46+0|ha=49+1195|u.ns=49@-1,0+0|ja=51+991|u.ns=51@-4,0+0|da=53+1063|pa.pas=53+830|na=56+989|dda.pas=56+0|ae.ns=56@-68,10+0|taling=60+677|ma=60+970|na=62+989|na.pas=62+0|i.ns_cecak.ns=62@-182,10+0|space=67+0|ma=68+970|sa=69+1088|ja.pas=69@200,0+0|i.ns=69@0,10+0|da=73+1063|pangkon=73+391|space=75+0|sha=76+938|u.ns=76+0|ra=78+915|ma=79+970|ba.pas=79@-1,0+0|i.ns=79@-62,10+0|space=83+0|sa=84+1088|ha=85+1195|space=86+0|pa=87+963|la=88+1194|ma=89+970|pa.pas=89+830|wignyan=89+353|ha=93+1195|na=94+989|pangkon=94+391|space=96+0|sa=97+1088|layar.ns=97@-208,10+0|ta=99+1183|space=100+0|taling=101+677|ba=101+1207|tarung=101+413|na=104+989|dda.pas=104+0|sa=107+1088|wa=108+967|ta=109+1183|wa=110+967|i.ns=110@-61,10+0|sa=112+1088|pangkon=112+391|space=114+0|ka=115+1221|taling=116+677|da=116+1063|tarung=116+413|sa=119+1088|ta.pas=119+0|uniA9C7=122+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BA,U+200B,U+A988,U+A9A9,U+A9C0,U+A9A7,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9B6,U+A9A4,U+A981,U+A994,U+A9B8,U+A9A4,U+A9C0,U+A9A0,U+A9A9,U+A9C0,U+A9A9,U+A9A4,U+A9C0,U+A9B1,U+A982,U+A9AB,U+A9B6,U+200B,U+A98F,U+A98A,U+A98F,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9A4,U+A9C0,U+A99B,U+A9B6,U+200B,U+A9A5,U+A99A,U+A9BC,U+A981,U+A98F,U+A9B8,U+A9AA,U+A9B8,U+A981,U+A994,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AA,U+A9AA,U+A9B1,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9C0,U+A9AD,U+A9B2,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9BC,U+200B,U+A992,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9B6,U+A9B2,U+A9A4,U+A9C0,U+A9B1,U+A9B2,U+200B,U+A98F,U+A982,U+A989,U+A9B1,U+A9C0,U+A9A9,U+A9BA,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A9,U+A9B6,U+A9A4,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+200B,U+A9AF,U+A9BF,U+A9B6,U+200B,U+A9AF,U+A9B8,U+A9AD,U+A9C0,U+A9A0,U+A9A4,U+A9C0,U+A9B2,U+A9A9,U+A981,U+A98F,U+A9B8,U+A9A8,U+A9B8,U+A9AE,U+A9A4,U+A9C7;[ma=0+1129|u.ns=0@-160,0+0|la=2+1194|ya.pas=2+0|ka=5+1221|ka.pas=5@-1,0+0|taling=8+677|ka=8+1221|space=10+0|ukara=11+976|ma=12+970|ba.pas=12@-1,0+0|u.ns.pas=12@-1,0+0|la=16+1194|ba.pas=16+0|i.ns=16@-70,10+0|na=20+989|cecak.ns=20@-330,10+0|nga=22+1098|u.ns=22@-122,0+0|na=24+989|ta.pas=24+0|ma=27+970|ma.pas=27@-1,0+0|na=30+989|sa.pas=30+830|layar.ns=30@-159,10+0|ra=34+915|i.ns=34@-62,10+0|space=36+0|ka=37+1221|ngalelet=38+977|ka=39+1221|sa.pas=39+830|na=42+1150|na.pas=42@-161,0+0|ka=45+1221|ka.pas=45@-1,0+0|ka=48+1221|ae.ns=48@-39,10+0|na=50+1150|ka.pas=50@-161,0+0|na=53+989|tta.pas=53+0|i.ns=53@-71,10+0|space=57+0|pa=58+963|nya=59+1439|ae.ns_cecak.ns=59@-102,10+0|ka=62+1221|u.ns=62@-1,0+0|ya=64+1383|u.ns=64@-1,0+0|cecak.ns=64@-333,10+0|nga=67+976|i.ns=67@-66,10+0|pa=69+1246|u.ns=69@-283,0+0|na=71+989|ya.pas=71+0|ya=74+1383|sa=75+1088|sa.pas=75+830|na=78+989|ka.pas=78+0|la=81+1194|la.pas=81@-278,0+0|ha=84+1195|u.ns=84@-1,0+0|sa=86+1088|ta.pas=86+0|ae.ns=86@3,10+0|space=90+0|ga=91+938|u.ns=91+0|la=93+1194|ba.pas=93+0|ae.ns=93@-67,10+0|na=97+989|ka.pas=97+0|i.ns=97@-71,10+0|ha=101+1195|na=102+989|sa.pas=102+830|ha=105+1195|space=106+0|ka=107+1221|layar.ns=107@-250,10+0|pacerek=109+963|taling=110+677|sa=110+1088|ma.pas=110+0|ka=114+1221|ka.pas=114@-1,0+0|ka=117+1221|ae.ns=117@-39,10+0|na=119+989|da.pas=119+0|i.ns=119@-71,10+0|na=123+989|i.ns_cecak.ns=123@-182,10+0|space=126+0|ha=127+1195|i.ns_cecak.ns=127@-182,10+0|ka=130+1221|cecak.ns=130@-301,10+0|space=132+0|ma=133+970|i.ns=133@-62,10+0|na=135+1148|u.ns=135@-159,0+0|la=137+1194|ya.pas=137+0|space=140+0|sha_cakra=141+1221|i.ns=141@58,10+0|space=144+0|sha=145+938|u.ns=145+0|la=147+1194|ta.pas=147+0|na=150+989|ha.pas=150+1090|ma=153+970|cecak.ns=153@-321,10+0|ka=155+1221|u.ns=155@-1,0+0|bha=157+879|u.ns=157@-37,0+0|wa=159+967|na=160+989|uniA9C7=161+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+0044,U+0072,U+A9C7,U+A9AF,U+A9B6,U+A9A9,U+A9C0,U+200B,U+A98F,U+A9B6,U+A984,U+A98C;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|.notdef=5+600|.notdef=6+600|uniA9C7=7+269|sha=8+938|i.ns=8@8,10+0|ma=10+970|pangkon=10+391|space=12+0|ka=13+1221|i.ns=13@-42,10+0|akara=15+1338|ekara=16+781]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+0049,U+0072,U+A9C7,U+A9AD,U+A9B6,U+A9A9,U+A9C0,U+200B,U+A986,U+A981,U+A9B2,U+A9C0,U+A9AE,U+A9B6;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|.notdef=5+600|.notdef=6+600|uniA9C7=7+269|la=8+1194|i.ns=8@-70,10+0|ma=10+970|pangkon=10+391|space=12+0|ikara=13+1207|cecak.ns=13@-293,10+0|ha=15+1195|wa.pas=15@-1,0+0|i.ns=15@-71,10+0]
diff --git a/test/shape/data/in-house/tests/use-syllable.tests b/test/shape/data/in-house/tests/use-syllable.tests
index 1cc52fd4f..e7cec5fc7 100644
--- a/test/shape/data/in-house/tests/use-syllable.tests
+++ b/test/shape/data/in-house/tests/use-syllable.tests
@@ -3,6 +3,7 @@
../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+AA35,U+AA33;[a_cham=0+1121|laMedial_cham=0@-32,0+0|yaMedial_cham=0+542]
../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+AA35,U+AA36;[a_cham=0+1121|laMedial_waMedial_cham=0@43,0+0]
../fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf;--no-glyph-names;U+11320,U+20F0,U+11367;[3=0+502|1=0@33,0+0|4=0@300,8+0]
+../fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf;;U+A8AC,U+A8B4,U+A8C4;[uniA8AC=0+586|uniA8B4=0+316|uniA8C4=0+0]
../fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf;--no-glyph-names;U+A8AC,U+A8B4,U+A8B5;[2=0+377|3=0+242|4=0+210]
../fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf;--no-glyph-names;U+1BC7,U+1BEA,U+1BF3;[1=0+749|2=0+402|4=0+535|3=0+401]
../fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf;;U+11064,U+1107F,U+11052,U+11065,U+1107F,U+11053;[brm_num100.1=0+2224|brm_num1000.2=3+1834]
@@ -20,3 +21,4 @@
../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+200C,U+AA34;[raMedial_cham_pre=0+400|a_cham=0+1121]
../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+200D,U+11127;[u11124=0+514|u11127=0+0]
../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+2060,U+11127;[u11124=0+514|uni25CC=1+547|u11127=1+0]
+../fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf;;U+1142C,U+11442,U+200C,U+1142E;[u1142C=0+547|u11442=0+0|u1142E=3+547]
diff --git a/test/shape/data/in-house/tests/use.tests b/test/shape/data/in-house/tests/use.tests
index ebeda4770..acbd59dc9 100644
--- a/test/shape/data/in-house/tests/use.tests
+++ b/test/shape/data/in-house/tests/use.tests
@@ -9,7 +9,9 @@
../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+11131,U+11134;[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0]
../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf;;U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443;[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0]
../fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf;;U+11328,U+1134D,U+1CF4;[gid1=0+793|gid2=0+0|gid3=0+0]
+../fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf;;U+11328,U+1133F,U+1134D,U+1CF4;[u11328=0+586|u1133F=0+316|uni25CC=0+652|u1134D=0+0|uni1CF4=0+0]
../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+1C00,U+1C27,U+1C28,U+1C34,U+1C35;[uni1C35=0+500|uni1C34=0+500|uni1C28=0+500|uni1C27=0+500|uni1C00=0+500]
../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D46;[uni0D15=0+500|uni0D4E=0+500|uni0D4D=0+500|uni0D46=3+500|uni0D15=3+500]
../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+1102D,U+11046,U+11013,U+11046,U+11013,U+11046;[u11013=0+500|u11046_u11013=0+500|u1102D_u11046=0+500|u11046=0+500]
../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+11083;[.notdef=0+500]
+../fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf;;U+11410,U+11441,U+11443;[E_dv.alt=0+275|Ga=0+576|AU_dv_part.alt=0+213|Candrabindu.sm=0@-52,179+0]
diff --git a/test/shape/data/in-house/tests/vertical.tests b/test/shape/data/in-house/tests/vertical.tests
index 22bf266ed..0e1b10672 100644
--- a/test/shape/data/in-house/tests/vertical.tests
+++ b/test/shape/data/in-house/tests/vertical.tests
@@ -1,4 +1,4 @@
../fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf;--direction=t --font-funcs=ft;U+300C;[uni300C.vert=0@-512,-578+0,-1024]
../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ft;U+0041,U+0042;[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
-../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ot;U+0041,U+0042;[gid1=0@-654,-1468+0,-2048|gid2=1@-665,-1462+0,-2048]
+../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ot;U+0041,U+0042;[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
../fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf;--direction=t --font-funcs=ot;U+FF38;[gid2=0@-500,-867+0,-1000]
diff --git a/test/shape/meson.build b/test/shape/meson.build
index dfc9f3297..beb6cd2c5 100644
--- a/test/shape/meson.build
+++ b/test/shape/meson.build
@@ -3,49 +3,52 @@ subdir('data/in-house') # in_house_tests
subdir('data/aots') # aots_tests
subdir('data/text-rendering-tests') # text_rendering_tests
-shaping_run_tests_py = find_program('run-tests.py')
+shape_run_tests_py = find_program('run-tests.py')
env = environment()
env.set('HAVE_FREETYPE', '@0@'.format(conf.get('HAVE_FREETYPE', 0)))
+env.set('HAVE_CORETEXT', '@0@'.format(conf.get('HAVE_CORETEXT', 0)))
+env.set('HAVE_DIRECTWRITE', '@0@'.format(conf.get('HAVE_DIRECTWRITE', 0)))
+env.set('HAVE_UNISCRIBE', '@0@'.format(conf.get('HAVE_UNISCRIBE', 0)))
foreach file_name : in_house_tests
test_name = file_name.split('.')[0]
- test(test_name, shaping_run_tests_py,
+ test(test_name, shape_run_tests_py,
args: [
hb_shape,
- join_paths(meson.current_source_dir(), 'data', 'in-house', 'tests', file_name),
+ meson.current_source_dir() / 'data' / 'in-house' / 'tests' / file_name,
],
env: env,
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
- suite: ['shaping', 'in-house'],
+ workdir: meson.current_build_dir() / '..' / '..',
+ suite: ['shape', 'in-house'],
)
endforeach
foreach file_name : aots_tests
test_name = file_name.split('.')[0]
- test(test_name, shaping_run_tests_py,
+ test(test_name, shape_run_tests_py,
args: [
hb_shape,
- join_paths(meson.current_source_dir(), 'data', 'aots', 'tests', file_name),
+ meson.current_source_dir() / 'data' / 'aots' / 'tests' / file_name,
],
env: env,
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
- suite: ['shaping', 'aots'],
+ workdir: meson.current_build_dir() / '..' / '..',
+ suite: ['shape', 'aots'],
)
endforeach
foreach file_name : text_rendering_tests
test_name = file_name.split('.')[0]
- test(test_name, shaping_run_tests_py,
+ test(test_name, shape_run_tests_py,
args: [
hb_shape,
- join_paths(meson.current_source_dir(), 'data', 'text-rendering-tests', 'tests', file_name),
+ meson.current_source_dir() / 'data' / 'text-rendering-tests' / 'tests' / file_name,
],
env: env,
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
- suite: ['shaping', 'text-rendering-tests'],
+ workdir: meson.current_build_dir() / '..' / '..',
+ suite: ['shape', 'text-rendering-tests'],
)
endforeach
diff --git a/test/shape/record-test.sh b/test/shape/record-test.sh
index 41e13c3c6..3c1717eba 100755
--- a/test/shape/record-test.sh
+++ b/test/shape/record-test.sh
@@ -19,6 +19,8 @@ if test "x$1" == 'x-o'; then
out=$1
shift
fi
+hb_subset=$1
+shift
hb_shape=$1
shift
fontfile=$1
@@ -27,6 +29,10 @@ if test "x${fontfile:0:1}" == 'x-'; then
exit 1
fi
shift
+if ! echo "$hb_subset" | grep -q 'subset'; then
+ echo "Specify hb-subset (or \"fonttools subset\"): got "$hb_subset"." >&2
+ exit 1
+fi
if ! echo "$hb_shape" | grep -q 'hb-shape'; then
echo "Specify hb-shape (not hb-view, etc): got "$hb_shape"." >&2
exit 1
@@ -61,7 +67,7 @@ fi
glyph_ids=`echo "$text" | $hb_shape $options --no-glyph-names --no-clusters --no-positions "$fontfile" | sed 's/[][]//g; s/|/,/g'`
cp "$fontfile" "$dir/font.ttf"
-echo fonttools subset \
+echo $hb_subset \
--glyph-names \
--no-hinting \
--layout-features='*' \
@@ -69,7 +75,7 @@ echo fonttools subset \
--text="$text" \
--output-file="$dir/font.subset.ttf" \
"$dir/font.ttf"
-fonttools subset \
+$hb_subset \
--glyph-names \
--no-hinting \
--layout-features='*' \
diff --git a/test/shape/run-tests.py b/test/shape/run-tests.py
index 83f1fec2e..03f03df6c 100755
--- a/test/shape/run-tests.py
+++ b/test/shape/run-tests.py
@@ -11,7 +11,10 @@ def shape_cmd(command):
args = sys.argv[1:]
-have_freetype = bool(int(os.getenv ('HAVE_FREETYPE', '1')))
+have_freetype = int(os.getenv ('HAVE_FREETYPE', 1))
+have_coretext = int(os.getenv ('HAVE_CORETEXT', 0))
+have_directwrite = int(os.getenv ('HAVE_DIRECTWRITE', 0))
+have_uniscribe = int(os.getenv ('HAVE_UNISCRIBE', 0))
if not args or args[0].find('hb-shape') == -1 or not os.path.exists (args[0]):
sys.exit ("""First argument does not seem to point to usable hb-shape.""")
@@ -82,6 +85,7 @@ for filename in args:
extra_options = ["--shaper=ot"]
if glyphs_expected != '*':
extra_options.append("--verify")
+ extra_options.append("--unsafe-to-concat")
if comment:
print ('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
@@ -91,6 +95,18 @@ for filename in args:
skips += 1
continue
+ if "--shaper=coretext" in options and not have_coretext:
+ skips += 1
+ continue
+
+ if "--shaper=directwrite" in options and not have_directwrite:
+ skips += 1
+ continue
+
+ if "--shaper=uniscribe" in options and not have_uniscribe:
+ skips += 1
+ continue
+
if "--font-funcs=ot" in options or not have_freetype:
glyphs1 = shape_cmd ([fontfile, "--font-funcs=ot"] + extra_options + ["--unicodes", unicodes] + options)
else:
@@ -105,6 +121,7 @@ for filename in args:
passes += 1
if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
+ print ("hb-shape", fontfile, "--unicodes", unicodes, file=sys.stderr)
print ("Actual: " + glyphs1, file=sys.stderr)
print ("Expected: " + glyphs_expected, file=sys.stderr)
fails += 1
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt
deleted file mode 100755
index b5b670fe1..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-‫دَر فارسی گَچْ‌پَژْ هست. این «ی» فارسی است.‬
-‫حرف «ع» را به چٰهار شکلِ «ع‍» و «‍ع‍» و «‍ع» و «‌ع‌» می‌توان نشان داد.‬
-‫تشخیصِ اِعْ‌ًٌَُراب ناهمخوان از وظایف حروفْ‌چین است.‬
-‫دو اِعراب همخوان مانند « َ» و « ّ» به شکل « َّ» باهم ترکیب می‌شوند.‬
-‫لازم است حروف‌چین رفتار درستی با کشیدهٔ یونی‌کدی داشته باشد.‬
-‫مثلاً بتواند کلـمهٔ «پیِٓـــــــچ» یا حروف «ــٖٓـ» را به درستی نمایش دهد.‬
-‫حرف «لام» و «الف» باید به شکل لیگاتوری نمایش داده شوند.‬
-‫کلمهٔ «بَلَاٰ» از آزمون‌های سطح پائین حروف‌چین است.‬ \ No newline at end of file
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
deleted file mode 100644
index 26f6f7b22..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-لًا
-ـلًا
-لاً
-ـلاً
-لّا
-ـلّا
-لاّ
-ـلاّ
-لًّا
-ـلًّا
-لاًّ
-ـلاًّ
-لَّا
-ـلَّا
-لاَّ
-ـلاَّ
-لَا
-ـلَا
-لاَ
-ـلاَ
-لُا
-ـلُا
-لاُ
-ـلاُ
-لِا
-ـلِا
-لاِ
-ـلاِ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
deleted file mode 100644
index 24eb0c91a..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
+++ /dev/null
@@ -1,695 +0,0 @@
-ـيًـ
-ـاً
-يُـ
-ـرً
-ـقًـ
-ـدً
-رً
-رٍ
-ـبًـ
-ـرّ
-مًـ
-ـضًـ
-مُـ
-ـدّ
-ـوّ
-ـمًـ
-ـتًـ
-ـيّـ
-يًـ
-تُـ
-ءً
-دً
-نًـ
-ـمُـ
-ـمّـ
-ةً
-حًـ
-ـوً
-ـحًـ
-ـرِّ
-ـةً
-نٍ
-ـمّ
-فًـ
-ـكّـ
-ـعًـ
-ـصًـ
-اً
-سِـ
-ـيُـ
-قِـ
-ـفًـ
-ـذّ
-ـجّـ
-بًـ
-غًـ
-ـلّـ
-ـصّـ
-ـلّ
-ـدَّ
-ـسِّـ
-ـزً
-وّ
-ـثًـ
-بُـ
-ـغّـ
-خِـ
-ـدِّ
-فٍ
-ـسّـ
-ـنًـ
-عًـ
-ـفّـ
-ـيَّـ
-ـلٍ
-ـطًـ
-ـبّـ
-ـطّـ
-ـجِّـ
-عُـ
-ـيّ
-ـنّـ
-كًـ
-ـلِـ
-ـئًـ
-جًـ
-ـذَّ
-قًـ
-ـنُـ
-ـخّـ
-ـتُـ
-رَ
-كّـ
-طًـ
-نُـ
-رّ
-لٍ
-ـضّـ
-بّـ
-عِـ
-زً
-مِـ
-ـكَّـ
-ـدَ
-ـدٍ
-أُ
-ـمَّـ
-ـأً
-ـرَ
-ـزّ
-حِـ
-مَـ
-ـيِّـ
-ـوَّ
-ـمَـ
-صًـ
-ضًـ
-ـرِ
-
-وُ
-يّ
-ـمِّـ
-ـيًّـ
-ـرَّ
-ـوِّ
-ـكًـ
-رِ
-ـلَّـ
-ـجِـ
-يَـ
-ـجَّـ
-ـاّ
-ـذً
-ـقّـ
-ـغِّـ
-ـخًـ
-ـسَّـ
-ـلٍّ
-ـهًـ
-قّـ
-حَـ
-ـجًـ
-ـفَّـ
-شُـ
-جّـ
-ـهّـ
-سَـ
-ـعّـ
-ـدِ
-دٍ
-رِّ
-ـذٍ
-ـبُّـ
-ـتَـ
-دُ
-ـتُ
-لّ
-سِّـ
-لّـ
-دّ
-دِ
-يٍّ
-جَـ
-نّ
-هَّـ
-ـكِّـ
-ـقِّـ
-ـعُـ
-بَـ
-تَـ
-ـنِّـ
-ـلُّـ
-ـسُـ
-مّـ
-قَّـ
-لَـ
-يّـ
-فُـ
-قٍ
-ـتٍ
-سّـ
-وَ
-ـسِـ
-ـتَ
-شِـ
-فَـ
-صُـ
-ـضَّـ
-تَ
-ـقَّـ
-ـطَّـ
-ـفِـ
-سًـ
-فّـ
-وَّ
-كُـ
-ـصَّـ
-عَـ
-لِـ
-ـقِ
-ـقٍ
-ـتّـ
-ـمْـ
-نّـ
-ـقَ
-وٍ
-ـطٍ
-ـةٍ
-هّـ
-هُـ
-ـوٍ
-ـبِـ
-رُ
-حّـ
-تّـ
-وِّ
-زُ
-ـلًـ
-ـفُّـ
-تٍ
-سُـ
-ضٍ
-بِـ
-خَـ
-ىً
-ضّـ
-ـبِّـ
-خّـ
-لًـ
-كَّـ
-ـظًـ
-ظًـ
-ةٍ
-ـغًـ
-ـكِـ
-طُـ
-ـنٍ
-ـقُـ
-ـبُـ
-دَ
-ثًـ
-فِـ
-يٍ
-نْـ
-ضِـ
-جُـ
-هٍ
-ـشِـ
-ـنَّـ
-يًّـ
-فِّـ
-ـفّ
-ـظّـ
-ـسَـ
-ـظِّـ
-ـبَّـ
-رْ
-تَّـ
-بٍ
-ـبَـ
-ـزُّ
-ـدُ
-ـكُـ
-طّـ
-صِـ
-تِـ
-ـغَّـ
-ـعَـ
-ـهِّـ
-ـرُ
-ـثّـ
-سَّـ
-ذً
-ـمَ
-ـلِّـ
-ـزِّ
-يٌّ
-قِّـ
-ـشِّـ
-ـسًـ
-شٍ
-سٍ
-تًـ
-ـلَـ
-ـحُـ
-ـصّ
-ـحِـ
-ـجُـ
-يَّـ
-لَّـ
-قَـ
-ـبْـ
-اِ
-وُّ
-ـشّـ
-خًـ
-ـسَ
-حُـ
-يْ
-نِـ
-كُّـ
-ـطُّـ
-سْـ
-زِ
-يَّ
-هِـ
-نَـ
-مَّـ
-مٍ
-كِـ
-ـيُّـ
-ـمِـ
-ـدٍّ
-ـحّـ
-ـتَّـ
-رِّ
-ـطّ
-ـرُّ
-عٍ
-زّ
-خَّـ
-قُـ
-ـشَـ
-ـحَـ
-ـجِّـ
-مَ
-ـيَّ
-ـقّ
-ـغِ
-ـطِ
-ـشُـ
-صّـ
-شّـ
-جِّـ
-جِـ
-وِ
-ـهِ
-ـهِـ
-ــّـ
-ـرٍ
-ـاًّ
-طَّـ
-ثُـ
-تُ
-بَّـ
-هَـ
-لْـ
-صَـ
-دْ
-يِـ
-كِّـ
-ـعِـ
-ـذَ
-ـةَ
-دَّ
-يِّ
-هًـ
-كْـ
-ـوَ
-ـقَّ
-ـؤّ
-زَ
-حٍ
-يْـ
-كَـ
-فِ
-ـهٍ
-ـنّ
-ـكِ
-ـضَـ
-ـصِـ
-صِّـ
-شِّـ
-رَّ
-يِّـ
-ـاَ
-عُ
-شَـ
-ئًـ
-مٌـ
-لُـ
-ـوِ
-ـقِـ
-ـقَـ
-ـخَـ
-ـةِ
-دِّ
-جْـ
-ةِ
-نْ
-لِّـ
-ـيَـ
-ـنَـ
-ـلٌ
-ـفِ
-ـزَّ
-ـزِ
-ـاِ
-عّـ
-حَّـ
-ثَـ
-أَ
-ـمٍ
-ـكُّـ
-عْـ
-صَّـ
-يٌـ
-مْـ
-مّ
-فُّـ
-ـنْـ
-ـمَّ
-ـكَـ
-ـصِّـ
-ـصَـ
-ـاَّ
-حْـ
-ثّـ
-اُ
-نِ
-كَ
-ـمِ
-ـلٌّ
-ـلِ
-ـلَ
-ـفَـ
-ـفٍ
-ـظَّـ
-ـزَ
-ـةُ
-ـأُ
-عَّـ
-شَّـ
-ـنِـ
-ـلُ
-ـطِّـ
-ـطَـ
-ـضِّـ
-ـصُـ
-ـسُّـ
-ـحُ
-ـثّ
-ـأَ
-ضَـ
-تْ
-اَ
-مًّـ
-ـيِـ
-ـهُـ
-ـمًّـ
-ـكْـ
-ـعْـ
-ـرِّ
-ـتِـ
-ـتً
-ـاُ
-غَـ
-عِ
-طً
-شًـ
-زٍ
-تِ
-بْـ
-بِ
-لِ
-قْـ
-قٌـ
-فّ
-ـىً
-ـلُّ
-ـلُـ
-ـفُـ
-ــُـ
-ـعَّـ
-ـشَّـ
-ـشًـ
-ـذِ
-ـدٌ
-طِـ
-طَـ
-ضَّـ
-صْـ
-رُّ
-ذُ
-جَّـ
-بِّـ
-ئِـ
-ءُ
-هُّـ
-مِّـ
-مُ
-كِ
-قُ
-فْـ
-ـيٍّ
-ـىَّ
-ـوِّ
-ـكَ
-ـعَ
-ـطَ
-ـسْـ
-ـرٌ
-ـذِّ
-ـدُّ
-ـخَّـ
-ـحْ
-ـجَـ
-ـثَّـ
-ـثُـ
-ـتّ
-ـبِ
-ـاْ
-ـإِ
-عَ
-طِّـ
-صُّـ
-زْ
-خِّـ
-خَ
-ثِـ
-تْـ
-تّ
-بٌـ
-ءَ
-ءٍ
-وْ
-نُ
-مِ
-كُ
-فْ
-ـوُّ
-ـلٍـ
-ـقٍّ
-ـفِّـ
-ـفًّـ
-ـعُ
-ـعٍ
-ـطْـ
-ـطِـ
-ـطُـ
-ـصٍ
-ـرْ
-ـرٍّ
-ـذُّ
-ـدْ
-ـدِّ
-ـخِـ
-ـجَّـ
-ـثْ
-ـتَّ
-ـةٌ
-سِ
-خْـ
-ثَ
-تُّـ
-تَّ
-إِ
-أّ
-أً
-ءِ
-ءٌ
-يُّـ
-يُّ
-نٌـ
-لْ
-لُ
-لَ
-قِ
-ـيًّ
-ـيَ
-ـهَّـ
-ـهِّـ
-ـنُّـ
-ـمٍّ
-ـلْـ
-ـلْ
-ـلٍّ
-ـكِّـ
-ـعّ
-ـطَّ
-ـضُـ
-ـضٍ
-ـضٌـ
-ـصْـ
-
-ـصُّـ
-ـصًّـ
-ـسًّـ
-ـدَّ
-ـثِّـ
-ـثِـ
-ـتِّـ
-ـبّ
-ـبَ
-ـأٌ
-غُـ
-ظَـ
-طْـ
-ضْـ
-ضِ
-صّ
-صِ
-شْـ
-سٌـ
-ذْ
-ذَ
-خِ
-خُـ
-خٌـ
-حِّـ
-حٌـ
-بِّ
-بُّ
-بَ
-يٍّ
-ىّ
-نِّـ
-نَّـ
-نٍـ
-نٌ
-مْ
-مٌ
-لُّـ
-قُّـ
-قّ
-فَّـ
-فُ
-فٍـ
-ـيْـ
-ـيَّـ
-ـيً
-ـىّ
-ـوُ
-ـهّ
-ـهَـ
-ـنُ
-ـنَ
-ـمَّـ
-ـلَّ
-ـقٌ
-ـفِّ
-ـفٍّ
-ـفًّ
-ــِّـ
-ــِ
-ــَـ
-ـغِـ
-ـغُـ
-ـغَـ
-ـعٌـ
-ـظّ
-ـظِـ
-ـظَ
-ـطٍّ
-ـطِّـ
-ـطُ
-ـضً
-ـصِ
-ـصَ
-ـصٌ
-ـشّ
-ـسّ
-ـسَّـ
-ـزْ
-ـزُ
-ـرًّ
-ـدًّ
-ـخُـ
-ـخُ
-ـحَّـ
-ـجْـ
-ـثِ
-ـثُ
-ـتْـ
-ـتْ
-ـتِ
-ـبْ
-ـبِّ
-ـبُّـ
-ـبُ
-ـبَّـ
-ـأٰ
-ـأِ
-ـأٍ
-غْـ
-غِّـ
-عْ
-ظِـ
-ضُ
-شّ
-سٍـ
-زِّ
-دُّ
-حْ
-حِ
-جُ
-ثُ
-تٌـ
-تٌ
-ةُ
-ةَ
-ةٌ
-أْ
-أِ
-أٌ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
deleted file mode 100644
index 00d9840d9..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-ـاً
-اً
-ـهٔ
-هٔ
-وِ
-پُـ
-ـلِ
-سِـ
-اِ
-اُ
-ـهُ
-ـرّ
-گِـ
-کِـ
-کُـ
-ژِ
-ـیِ
-ـنِـ
-ـمُ
-ـصّـ
-ـسّـ
-رِ
-دّ
-دِ
-یِ
-هّ
-لِـ
-لِ
-ـیٰ
-ـیّ
-ـیَـ
-ـنِ
-ـمّـ
-ـعّـ
-ـشِ
-ـسِ
-ـزّ
-ـرِ
-ـذّ
-ـخّـ
-ـحِ
-ـثْ
-ـبّـ
-ـبّ
-ـأُ
-تّـ
-تِ
-بُـ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
deleted file mode 100644
index fddb6e52a..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
+++ /dev/null
@@ -1,188 +0,0 @@
-ـیّـ
-ـمّـ
-ـلّـ
-ـرّ
-ـاً
-ـلِـ
-ـرِ
-بُـ
-ـوّ
-ؤ
-اً
-اِ
-ـنّـ
-ثّـ
-ـجّـ
-پُـ
-ـصّـ
-ـہٰـ
-ـعّـ
-ـخّـ
-یَـ
-کُـ
-جّـ
-ـنٰـ
-ـظّـ
-دّ
-ـھّـ
-اُ
-کِـ
-لِـ
-بِـ
-نِـ
-لُـ
-ـلٰـ
-ـدّ
-مّـ
-گُـ
-ـوِ
-ـسّـ
-سُـ
-رِ
-ـھُـ
-مِـ
-يُـ
-ـطّـ
-شِـ
-سَـ
-ـگَـ
-زُ
-ـگُـ
-ئِـ
-قّـ
-قِـ
-ـفّـ
-خّـ
-نّـ
-ـبّـ
-ہِ
-تّـ
-بَـ
-فِـ
-بّـ
-ـیٰ
-ـٹّـ
-وَ
-چّـ
-پِـ
-لّـ
-دُ
-ـلِ
-ـبٰـ
-ـچّـ
-سِـ
-کّـ
-ٹِـ
-وِ
-ـی٘ـ
-ـۂ
-ـوٰ
-وّ
-ـۓ
-ـکّـ
-نِ
-مُـ
-ـتّـ
-دِ
-یِـ
-ہِـ
-گَـ
-پَـ
-ٹّ
-یٔ
-یّـ
-ہُـ
-چُـ
-مِ
-ـوُ
-ـاَ
-اَ
-گِـ
-فِ
-ـےٍ
-ـڈّ
-ـؤ
-ـقّـ
-ـجِ
-اٰ
-ـڈِ
-ـپّـ
-ـٹِـ
-ـمِـ
-ـلٔـ
-ـخِ
-رُ
-تِ
-بِ
-ۓ
-کَـ
-ٹُـ
-ـی٘
-ـںَ
-ـو٘
-ـنُـ
-ـعّ
-ـشّـ
-ـرُ
-ـحّـ
-ـجِـ
-ـبَـ
-طّـ
-شِ
-شُـ
-رّ
-جِـ
-ئٰـ
-ہٰـ
-ۂ
-ڈِ
-ڈُ
-چِـ
-نِّـ
-نُـ
-نَـ
-مٰـ
-مّ
-مَـ
-لِّـ
-لِ
-فّـ
-ـیّ
-ـیِـ
-ـہ٘ـ
-ـہّ
-ـہِـ
-ـں٘
-ـگِـ
-ـکٰـ
-ـکِـ
-ـٹَـ
-ـيّـ
-ـوَ
-ـنِـ
-ـفِـ
-ـصِ
-ـسِـ
-ـزّ
-ـرً
-ـدَ
-ـحِـ
-ـحِ
-ـتّٰـ
-ـتِ
-ـبُـ
-ـأ
-عُـ
-ظِ
-صّـ
-صُـ
-زِ
-رَ
-دِّ
-خُـ
-حِ
-حَـ
-جّ
-جُـ
-جَـ
-تَـ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
deleted file mode 100644
index 0d4d47fb5..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-لّله
-لَّله
-لَّله
-للّه
-للَّه
-للَّه
-للهّ
-للهَّ
-للهَّ
-لّلَه
-لَلّه
-لّلهَ
-لَلهّ
-للّهَ
-للَهّ
-لّلّهَ
-لّلَّه
-لَّلّه
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
deleted file mode 100644
index 80ba2f735..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
+++ /dev/null
@@ -1 +0,0 @@
-لَا لا لِله للَه لله
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
deleted file mode 100644
index 038c92124..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-تختة
-تخنة
-تخئة
-تخثة
-تخٹة
-تختّة
-تخنّة
-تخئّة
-تخثّة
-تخٹّة
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
deleted file mode 100644
index 57317de83..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌
-ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ
-ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ
-ᠡ᠆ᠡ
-ᠡ᠇ᠡ
-ᠡ᠊ᠡ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt
deleted file mode 100644
index 93e9dd6b7..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-ᠡᢀᠡ
-ᠡᢁᠡ
-ᠡᢂᠡ
-ᠡᢃᠡ
-ᠡᢄᠡ
-ᠡᢅᠡ
-ᠡᢆᠡ
-ᠡᢇᠡ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
deleted file mode 100644
index 14ce2d45f..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ᠥᠰᠬᠦ ᠡᠴᠡ ᠰᠤᠷᠤᠭᠰᠠᠨ ᠦᠨᠳᠦᠰᠦᠨ ᠬᠡᠯᠡ
-ᠮᠠᠷᠲᠠᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠰᠣᠶᠣᠯ
-ᠦᠬᠦᠲᠡᠯ᠎ᠡ ᠣᠷᠣᠰᠢᠬᠤ ᠲᠦᠷᠦᠯᠬᠢ ᠨᠤᠲᠤᠭ
-ᠰᠠᠯᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠣᠷᠣᠨ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt
deleted file mode 100644
index 0ffb49862..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-ᠺᠣᠮᠫᠢᠦ᠋ᠲ᠋ᠧᠷ
-ᠭ ᠭ᠋ ᠭ᠌ ᠭ᠍‍ isol(,FVS1,FVS2,FVS3)
-ᠭ‍ ᠭ᠋‍ ᠭ᠌‍ ᠭ᠍‍ init(,FVS1,FVS2,FVS3)
-‍ᠭ‍ ‍ᠭ᠋‍ ‍ᠭ᠌‍ ‍ᠭ᠍‍ medi(,FVS1,FVS2,FVS3)
-‍ᠭ ‍ᠭ᠋ ‍ᠭ᠌ fina(,FVS1,FVS2)
-ᠠ‌ᠭᠠᠷ ZWNJ
-ᠰᠤᠷ‍ ‍ᠭᠠ‍ ‍ᠭᠤᠯᠢ ZWJ
-ᠪᠠᠢᠭ᠎ᠠ ᠶᠢᠨ MVS,NNBSP
diff --git a/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
deleted file mode 100644
index a86af9140..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-ߊߊ
-ߊ߳ߊ
-ߊ߳ߺߊ
-ߊߺߊ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt
deleted file mode 100644
index d535b6726..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-ꡳꡡ
-ꡡꡳꡡ
-ꡞꡞꡞ ꡞ
-ꡟꡟꡟ ꡟ
-ꡠꡠꡠ ꡠ
-ꡡꡡꡡ ꡡ
-‍ꡡ‍
-‍ꡡ
-ꡡ‍
-ꡞ‌ꡟ‌ꡠ‌ꡡ
-ꡉꡞ
-ꡉꡞ︀
-ꡪꡞ
-ꡪꡞ︀
diff --git a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt b/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
deleted file mode 100644
index 52bdbea3c..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-ܐܒ
-ܐ܏
-ܐ܏ܒ
-ܐ܏ܒܓ
-ܐ܏ܒܓܕ
-ܐ܏ܒܓܕܐ
-ܐ܏ܒܓܕܐܐܐܐܐܐܐܐܐ
-ܐ܏ܒܓܕܐ܏ܐܐܐ܏ܐ܏ܐܐܐܐ
-ܐ܏ܒܓܕܓܓܓܓܓܓ
-ܐ܏ܒܓ
-܏ܫܘabcܒ.
diff --git a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt b/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
deleted file mode 100644
index 27b035f70..000000000
--- a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
+++ /dev/null
@@ -1,98 +0,0 @@
- ܐ
- ܐܘ
- ܐܪ
- ܐܖ
- ܐܕ
- ܐܯ
- ܐܒ
-ܘܐ
-ܘܐܘ
-ܘܐܪ
-ܘܐܖ
-ܘܐܕ
-ܘܐܯ
-ܘܐܒ
-ܪܐ
-ܪܐܘ
-ܪܐܪ
-ܪܐܖ
-ܪܐܕ
-ܪܐܯ
-ܪܐܒ
-ܖܐ
-ܖܐܘ
-ܖܐܪ
-ܖܐܖ
-ܖܐܕ
-ܖܐܯ
-ܖܐܒ
-ܕܐ
-ܕܐܘ
-ܕܐܪ
-ܕܐܖ
-ܕܐܕ
-ܕܐܯ
-ܕܐܒ
-ܯܐ
-ܯܐܘ
-ܯܐܪ
-ܯܐܖ
-ܯܐܕ
-ܯܐܯ
-ܯܐܒ
-ܒܐ
-ܒܐܘ
-ܒܐܪ
-ܒܐܖ
-ܒܐܕ
-ܒܐܯ
-ܒܐܒ
- ܐܐ
- ܐܐܘ
- ܐܐܪ
- ܐܐܖ
- ܐܐܕ
- ܐܐܯ
- ܐܐܒ
-ܘܐܐ
-ܘܐܐܘ
-ܘܐܐܪ
-ܘܐܐܖ
-ܘܐܐܕ
-ܘܐܐܯ
-ܘܐܐܒ
-ܪܐܐ
-ܪܐܐܘ
-ܪܐܐܪ
-ܪܐܐܖ
-ܪܐܐܕ
-ܪܐܐܯ
-ܪܐܐܒ
-ܖܐܐ
-ܖܐܐܘ
-ܖܐܐܪ
-ܖܐܐܖ
-ܖܐܐܕ
-ܖܐܐܯ
-ܖܐܐܒ
-ܕܐܐ
-ܕܐܐܘ
-ܕܐܐܪ
-ܕܐܐܖ
-ܕܐܐܕ
-ܕܐܐܯ
-ܕܐܐܒ
-ܯܐܐ
-ܯܐܐܘ
-ܯܐܐܪ
-ܯܐܐܖ
-ܯܐܐܕ
-ܯܐܐܯ
-ܯܐܐܒ
-ܒܐܐ
-ܒܐܐܘ
-ܒܐܐܪ
-ܒܐܐܖ
-ܒܐܐܕ
-ܒܐܐܯ
-ܒܐܐܒ
diff --git a/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
deleted file mode 100644
index 60dd8cc98..000000000
--- a/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
+++ /dev/null
@@ -1 +0,0 @@
-ላ፟ህ
diff --git a/test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt b/test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt
deleted file mode 100644
index b3ab64570..000000000
--- a/test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-艹
-艹
-艹
diff --git a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt b/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
deleted file mode 100644
index 5bc2d003a..000000000
--- a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-ありあるあれいているべきいろうれし
-うれしくかしこかとがとうくもこと
-こともことをこのこれこれもされ
-しかししてするせんたしたのちる
-とけとしとしてとのともかくとを
-なくなどなどのなるひさひとふるほど
-ますむとめてもしろものをやるゆる
-られるとるものれる〳〵〴〵
diff --git a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt b/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt
deleted file mode 100644
index e043e173d..000000000
--- a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-あり
-ある
-あれ
-いて
-いるべき
-いろ
-うれし
-うれしく
-かしこ
-かと
-がとう
-くも
-こと
-ことも
-ことを
-この
-これ
-これも
-され
-しかし
-して
-する
-せん
-たし
-たの
-ちる
-とけ
-とし
-として
-との
-ともかく
-とを
-なく
-など
-などの
-なる
-ひさ
-ひと
-ふる
-ほど
-ます
-むと
-めて
-もしろ
-ものを
-やる
-ゆる
-られ
-ると
-るもの
-れる
-〳〵
-〴〵
diff --git a/test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt
deleted file mode 100644
index b085605e7..000000000
--- a/test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt
+++ /dev/null
@@ -1 +0,0 @@
-𐀁𐀂𐀃
diff --git a/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
deleted file mode 100644
index 9fc069a34..000000000
--- a/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-ⵎⵜ
-ⵎ⵿ⵜ
-ⵏⴾ
-ⵏ⵿ⴾ
-ⵏⵜ
-ⵏ⵿ⵜ
-ⵔⵜ
-ⵔ⵿ⵜ
-ⵙⵜ
-ⵙ⵿ⵜ
diff --git a/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt b/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
deleted file mode 100644
index 797b1c69f..000000000
--- a/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-휴가 가-- (오--)
-휴가 가-- (오--)
-ᄒᆞᆫ
-ᅟᅡᄫᅠ
diff --git a/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt b/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
deleted file mode 100644
index f3cf91fa8..000000000
--- a/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-קול דודי הנה־זה בא מדלג על־ההרים מקפץ על־הגבעות
-הֲבֵל הֲבָלִים אָמַר קֹהֶלֶת
-לְהַגִּיד בַּבֹּקֶר חַסְדֶּךָ וֶאֱמוּנָתְךָ בַּלֵּילוֹת
-יְרוּשָׁלִַם
-יְרוּשָׁלִָם
-יְרוּשָׁלְַמָה
-יְרוּשָׁלְָמָה
-נְבֻֽכַדְנֶאצַּ֣ר
-מִתָּ֑͏ַ֜חַת
-אֲ‍ֽ֭דַבְּרָה
-וֽ͏ַיְהִי־֯כֵֽן
-לׅׄוּלֵׅ֗ׄאׅׄ
-אָנָּֽה אָנָּֽה
-תַעֲשֶׂ֦ה
-שֹֽׁטְרֵי֙
-אֲ‍ֽ֭
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index 2bc4fff7e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ৠ
-ৡ
-ৢ
-ৣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 0f8fa91d6..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-ক
-খ
-গ
-ঘ
-ঙ
-চ
-ছ
-জ
-ঝ
-ঞ
-ট
-ঠ
-ড
-ঢ
-ণ
-ত
-থ
-দ
-ধ
-ন
-প
-ফ
-ব
-ভ
-ম
-য
-ৰ
-ৱ
-ল
-ড়
-ঢ়
-য়
-শ
-ষ
-স
-হ
-ৎ
-ং
-ঃ
-ঁ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index ddf03c0aa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-া
-ি
-ী
-ু
-ূ
-ৃ
-ে
-ৈ
-ো
-ৌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 870ce26aa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-০
-১
-২
-৩
-৪
-৫
-৬
-৭
-৮
-৯
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 821c2615f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-অ
-আ
-ই
-ঈ
-উ
-ঊ
-ঋ
-এ
-ঐ
-ও
-ঔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 0afc191b2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-্
-়
-ং
-ঃ
-ঁ
-৺
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index ebbc87d0a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-কঁ
-খঁ
-গঁ
-ঘঁ
-চঁ
-ছঁ
-জঁ
-ঝঁ
-টঁ
-ঠঁ
-ডঁ
-ঢঁ
-তঁ
-থঁ
-দঁ
-ধঁ
-পঁ
-ফঁ
-বঁ
-ভঁ
-মঁ
-যঁ
-ৰঁ
-লঁ
-শঁ
-ষঁ
-সঁ
-হঁ
-ৰ্ক
-ৰ্খ
-ৰ্গ
-ৰ্ঘ
-ৰ্চ
-ৰ্ছ
-ৰ্জ
-ৰ্ঝ
-ৰ্ঞ
-ৰ্ট
-ৰ্ঠ
-ৰ্ড
-ৰ্ঢ
-ৰ্ণ
-ৰ্ত
-ৰ্থ
-ৰ্দ
-ৰ্ধ
-ৰ্ন
-ৰ্প
-ৰ্ফ
-ৰ্ব
-ৰ্ভ
-ৰ্ম
-ৰ্য
-ৰ্ৰ
-ৰ্ল
-ৰ্শ
-ৰ্ষ
-ৰ্স
-ৰ্হ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index accebebcf..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,131 +0,0 @@
-কু
-কূ
-কৃ
-খু
-খূ
-খৃ
-গু
-গূ
-গৃ
-ঘু
-ঘূ
-ঘৃ
-ঙু
-ঙূ
-ঙৃ
-চু
-চূ
-চৃ
-ছু
-ছূ
-ছৃ
-জু
-জূ
-জৃ
-ঝু
-ঝূ
-ঝৃ
-ঞু
-ঞূ
-টু
-টূ
-টৃ
-ঠু
-ঠূ
-ঠৃ
-ডু
-ডূ
-ডৃ
-ঢু
-ঢূ
-ঢৃ
-ণু
-ণূ
-ণৃ
-তু
-তূ
-তৃ
-থু
-থূ
-থৃ
-দু
-দূ
-দৃ
-ধু
-ধূ
-ধৃ
-নু
-নূ
-নৃ
-পু
-পূ
-পৃ
-ফু
-ফূ
-ফৃ
-বু
-বূ
-বৃ
-ভু
-ভূ
-ভৃ
-মু
-মূ
-মৃ
-যু
-যূ
-যৃ
-ৰু
-ৰূ
-ৰৃ
-লু
-লূ
-লৃ
-শু
-শূ
-শৃ
-ষু
-ষূ
-ষৃ
-সু
-সূ
-সৃ
-হু
-হূ
-হৃ
-ক্
-খ্
-গ্
-ঘ্
-ঙ্
-চ্
-ছ্
-জ্
-ঝ্
-ঞ্
-ট্
-ঠ্
-ড্
-ঢ্
-ণ্
-ত্
-থ্
-দ্
-ধ্
-ন্
-প্
-ফ্
-ব্
-ভ্
-ম্
-য্
-ৰ্
-ল্
-শ্
-ষ্
-স্
-হ্
-জ়
-ড়
-ঢ়
-য়
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 87e5ea895..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,139 +0,0 @@
-ক্ৰ
-খ্ৰ
-গ্ৰ
-ঘ্ৰ
-জ্ৰ
-ত্ৰ
-দ্ৰ
-ধ্ৰ
-প্ৰ
-ম্ৰ
-শ্ৰ
-স্ৰ
-হ্ৰ
-ক্ল
-গ্ল
-প্ল
-ম্ল
-ল্ল
-শ্ল
-স্ল
-হ্ল
-ক্ক
-ক্ব
-জ্ব
-ট্ব
-ত্ব
-দ্ব
-ধ্ব
-ন্ব
-ব্ব
-ম্ব
-ল্ব
-শ্ব
-ষ্ব
-স্ব
-হ্ব
-ণ্ণ
-ষ্ণ
-ষ্ণু
-হ্ণ
-হ্ণি
-জ্জ
-ট্ট
-ত্ত
-দ্দ
-ন্ন
-প্প
-ব্ব
-ম্ম
-ত্ন
-ম্ন
-স্ন
-হ্ন
-ক্ন
-গ্ন
-ত্ম
-গ্ম
-ঙ্ম
-ট্ম
-ণ্ম
-ত্ম
-দ্ম
-ধ্ম
-ন্ম
-ম্ম
-ল্ম
-শ্ম
-ষ্ম
-হ্ম
-ক্ষ
-ক্ত
-গ্ধ
-ঙ্ক
-ঙ্খ
-ঙ্গ
-ঙ্ঘ
-চ্চ
-চ্ছ
-চ্ঞ
-জ্ঝ
-জ্ঞ
-ঞ্চ
-ঞ্ছ
-ঞ্জ
-ণ্ট
-ক্ট
-ণ্ড
-ন্ড
-দ্গ
-দ্ঘ
-দ্ধ
-দ্ভ
-ন্ত
-ন্থ
-ন্দ
-ন্ধ
-প্ত
-ব্জ
-ব্দ
-ম্প
-ম্ফ
-ম্ব
-ম্ভ
-ল্ক
-ল্গ
-ল্প
-ল্ফ
-ল্ম
-শ্চ
-ষ্ক
-ষ্ট
-ষ্ঠ
-ষ্প
-ষ্ফ
-স্ক
-স্খ
-স্ত
-স্থ
-স্প
-স্ফ
-ক্ষ্ণ
-ক্ষ্ম
-জ্জ্ব
-ত্ত্ব
-ত্ম্য
-ন্ত্ৰ
-ন্ত্ব
-ন্দ্ৰ
-ন্ধ্য
-ন্ন্য
-ম্প্ৰ
-ম্ভ্ৰ
-ৰ্ধ্ব
-ৰ্শ্ব
-ষ্ট্ৰ
-ষ্প্ৰ
-স্ত্ৰ
-চ্ছ্ব
-প্স
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
deleted file mode 100644
index f09dbc8f5..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-আ অা
-ৠ ঋৃ
-ৡ ঌৢ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
deleted file mode 100644
index aa4359086..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-অ্য
-ক
-ক়
-কি
-ক্
-ক্ক
-ক্র
-ক্র্ক
-ক্‌ক
-ক্‍ক
-দ্য
-ন্ক
-ন্ধ
-ন্ব
-ন্য
-ন্র
-ন্‌ক
-ন্‌ধ
-ন্‌ব
-ন্‌র
-ন্‍ক
-ন্‍ধ
-ন্‍ব
-ন্‍র
-য্
-র্ক
-র্কি
-র্কৌ
-র্ন্‍
-র্ব্ব
-শ্য
-ষ্য
-স্য
-ি
-কো
-কৌ
-ক্র্ক
-ন্‌ক
-ন্‌ব
-ন্‍ক
-ন্‍ব
-ন্‍র
-র্কাং
-র্কাঃ
-র্কৌ
-র্ভ
-ৰ্ভ
-ৱ্ভ
-অৗ
-ন্ত্র
-ত্যু
-চ্য্র
-ক্‍ষ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
deleted file mode 100644
index 9739eaa06..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-র্ক
-র্কা
-র্কি
-র্কী
-র্কু
-র্কূ
-র্কে
-র্কৈ
-র্কো
-র্কৌ
-র্য
-র্‍য
-র‍্য
-র্র‍্য
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index fd5e6e68b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 7554b3640..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-ক
-খ
-গ
-ঘ
-ঙ
-চ
-ছ
-জ
-ঝ
-ঞ
-ট
-ঠ
-ড
-ঢ
-ণ
-ত
-থ
-দ
-ধ
-ন
-প
-ফ
-ব
-ভ
-ম
-য
-র
-ল
-ড়
-ঢ়
-য়
-শ
-ষ
-স
-হ
-ৎ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index ddf03c0aa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-া
-ি
-ী
-ু
-ূ
-ৃ
-ে
-ৈ
-ো
-ৌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 870ce26aa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-০
-১
-২
-৩
-৪
-৫
-৬
-৭
-৮
-৯
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 169ba5dec..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-অ
-আ
-ই
-ঈ
-উ
-ঊ
-ঋ
-ঌ
-এ
-ঐ
-ও
-ঔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 0afc191b2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-্
-়
-ং
-ঃ
-ঁ
-৺
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 7c652be8e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-কঁ
-খঁ
-গঁ
-ঘঁ
-চঁ
-ছঁ
-জঁ
-ঝঁ
-টঁ
-ঠঁ
-ডঁ
-ঢঁ
-তঁ
-থঁ
-দঁ
-ধঁ
-পঁ
-ফঁ
-বঁ
-ভঁ
-মঁ
-যঁ
-রঁ
-লঁ
-শঁ
-ষঁ
-সঁ
-হঁ
-র্ক
-র্খ
-র্গ
-র্ঘ
-র্চ
-র্ছ
-র্জ
-র্ঝ
-র্ট
-র্ঠ
-র্ড
-র্ঢ
-র্ণ
-র্ত
-র্থ
-র্দ
-র্ধ
-র্ন
-র্প
-র্ফ
-র্ব
-র্ভ
-র্ম
-র্য
-র্র
-র্ল
-র্শ
-র্ষ
-র্স
-র্হ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index 2fd42e00b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-কু
-কূ
-কৃ
-খু
-খূ
-খৃ
-গু
-গূ
-গৃ
-ঘু
-ঘূ
-ঘৃ
-চু
-চূ
-চৃ
-ছু
-ছূ
-ছৃ
-জু
-জূ
-জৃ
-ঝু
-ঝূ
-ঝৃ
-টু
-টূ
-টৃ
-ঠু
-ঠূ
-ঠৃ
-ডু
-ডূ
-ডৃ
-ঢু
-ঢূ
-ণু
-ণূ
-তু
-তূ
-তৃ
-থু
-থূ
-দু
-দূ
-দৃ
-ধু
-ধূ
-ধৃ
-নু
-নূ
-নৃ
-পু
-পূ
-পৃ
-ফু
-ফূ
-ফৃ
-বু
-বূ
-বৃ
-ভু
-ভূ
-ভৃ
-মু
-মূ
-মৃ
-যু
-যূ
-যৃ
-রু
-রূ
-রৃ
-লু
-লূ
-শু
-শূ
-শৃ
-ষু
-ষূ
-ষৃ
-সু
-সূ
-সৃ
-হু
-হূ
-হৃ
-ক্
-খ্
-গ্
-ঘ্
-ঙ্
-চ্
-ছ্
-জ্
-ঝ্
-ঞ্
-ট্
-ঠ্
-ড্
-ঢ্
-ণ্
-ত্
-থ্
-দ্
-ধ্
-ন্
-প্
-ফ্
-ব্
-ভ্
-ম্
-য্
-র্
-ল্
-শ্
-ষ্
-স্
-হ্
-জ়
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index b45b7780b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,215 +0,0 @@
-ক্র
-খ্র
-গ্র
-ঘ্র
-জ্র
-ত্র
-দ্র
-ধ্র
-প্র
-ম্র
-শ্র
-স্র
-হ্র
-ছ্র
-ট্র
-ঠ্র
-ড্র
-থ্র
-ফ্র
-ব্র
-ভ্র
-ক্য
-খ্য
-গ্য
-ঘ্য
-চ্য
-জ্য
-ট্য
-ঠ্য
-ড্য
-ড়্য
-ঢ্য
-ত্য
-থ্য
-দ্য
-ধ্য
-ন্য
-প্য
-ফ্য
-ব্য
-ভ্য
-ম্য
-য্য
-র‍্য
-ল্য
-শ্য
-ষ্য
-স্য
-হ্য
-ক্ল
-গ্ল
-প্ল
-ম্ল
-ল্ল
-শ্ল
-স্ল
-হ্ল
-ক্ক
-ক্ব
-জ্ব
-ট্ব
-ত্ব
-দ্ব
-ধ্ব
-ন্ব
-ব্ব
-ম্ব
-ল্ব
-শ্ব
-ষ্ব
-স্ব
-হ্ব
-ণ্ণ
-ষ্ণ
-ষ্ণু
-হ্ণ
-হ্ণি
-জ্জ
-ট্ট
-ত্ত
-দ্দ
-ন্ন
-প্প
-ত্ন
-ম্ন
-স্ন
-হ্ন
-ক্ন
-গ্ন
-গ্ম
-ঙ্ম
-ট্ম
-ণ্ম
-ত্ম
-দ্ম
-ধ্ম
-ন্ম
-ম্ম
-ল্ম
-শ্ম
-ষ্ম
-হ্ম
-ক্ষ
-ক্ত
-গ্ধ
-ঙ্ক
-ঙ্খ
-ঙ্গ
-ঙ্ঘ
-চ্চ
-চ্ছ
-চ্ঞ
-জ্ঝ
-জ্ঞ
-ঞ্চ
-ঞ্ছ
-ঞ্জ
-ণ্ট
-ক্ট
-ণ্ড
-ন্ড
-দ্গ
-দ্ঘ
-দ্ধ
-দ্ভ
-ন্ত
-ন্থ
-ন্দ
-ন্ধ
-প্ত
-ব্জ
-ব্দ
-ম্প
-ম্ফ
-ম্ভ
-ল্ক
-ল্গ
-ল্প
-ল্ফ
-শ্চ
-ষ্ক
-ষ্ট
-ষ্ঠ
-ষ্প
-ষ্ফ
-স্ক
-স্খ
-স্ত
-স্থ
-স্প
-স্ফ
-ম্থ
-ল্ত
-ল্ধ
-ক্ম
-ক্স
-গ্গ
-ঘ্ন
-চ্ন
-ছ্ব
-ঞ্ঝ
-ড্ড
-ড্ম
-ড়্গ
-ণ্ঠ
-ণ্ঢ
-ণ্ব
-ত্থ
-থ্ব
-ধ্ন
-ন্ট
-ন্ঠ
-ন্স
-প্ট
-প্ন
-ফ্ল
-ব্ধ
-ব্ল
-ভ্ল
-ম্ত
-ম্দ
-ল্ট
-ল্ড
-শ্ছ
-শ্ন
-শ্ত
-স্ট
-স্ম
-চ্ছ্র
-চ্ছ্ব
-দ্দ্ব
-দ্ধ্ব
-ন্ধ্র
-ব্দ্র
-ক্ষ্ণ
-ক্ষ্ম
-জ্জ্ব
-ত্ত্ব
-ত্ম্য
-ন্ত্র
-ন্ত্ব
-ন্দ্র
-ন্ধ্য
-ন্ন্য
-ম্প্র
-ম্ভ্র
-র্ধ্ব
-র্শ্ব
-ষ্ট্র
-ষ্প্র
-স্ত্র
-স্ট্র
-স্ক্র
-ক্ট্র
-প্স
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
deleted file mode 100644
index 426543658..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-ख ख्ा ख्‍ा
-ग ग्ा ग्‍ा
-घ घ्ा घ्‍ा
-च च्ा च्‍ा
-ज ज्ा ज्‍ा
-झ झ्ा झ्‍ा
-ञ ञ्ा ञ्‍ा
-ण ण्ा ण्‍ा
-त त्ा त्‍ा
-थ थ्ा थ्‍ा
-ध ध्ा ध्‍ा
-न न्ा न्‍ा
-ऩ ऩ्ा ऩ्‍ा ऩ्ा ऩ्‍ा
-प प्ा प्‍ा
-ब ब्ा ब्‍ा
-भ भ्ा भ्‍ा
-म म्ा म्‍ा
-य य्ा य्‍ा
-ल ल्ा ल्‍ा
-व व्ा व्‍ा
-श श्ा श्‍ा
-ष ष्ा ष्‍ा
-स स्ा स्‍ा
-ख़ ख़्ा ख़्‍ा ख़्ा ख़्‍ा
-ग़ ग़्ा ग़्‍ा ग़्ा ग़्‍ा
-ज़ ज़्ा ज़्‍ा ज़्ा ज़्‍ा
-य़ य़्ा य़्‍ा य़्ा य़्‍ा
-ॹ ॹ्ा ॹ्‍ा
-ॺ ॺ्ा ॺ्‍ा
-ज़ ॻ्ा ॻ्‍ा
-ॼ ॼ्ा ॼ्‍ा
-ॾ ॾ्ा ॾ्‍ा
-ॿ ॿ्ा ॿ्‍ा
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
deleted file mode 100644
index 5a41252f2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-ऄ अॆ
-आ अा
-ई र्इ
-ऊ उु
-ऍ एॅ
-ऎ एॆ
-ऐ एे
-ऑ अॉ आॅ
-ऒ अॊ आॆ
-ओ अो आे
-औ अौ आै
-ॲ अॅ
-ॳ अऺ
-ॴ अऻ आऺ
-ॵ अॏ
-ॶ अॖ
-ॷ अॗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
deleted file mode 100644
index fd0ebdbf0..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-र्◌
-र्◌्च
-र्◌्च्छे
-र्◌ि
-र्◌्
-र्◌़
-◌्च्छे
-र् 
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
deleted file mode 100644
index 8e1195567..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-त्र्क
-त्र्‍क
-त्र्‌क
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
deleted file mode 100644
index 75f85cc88..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-र्ह
-र्‌ह
-र्‍ह
-ऱ्ह
-ऱ्‌ह
-ऱ्‍ह
-क्क
-क्‍
-क्‌क
-क्‍क
-क्कि
-क्‌कि
-क्‍कि
-क्ष
-क्‌ष
-क्‍ष
-द्सि
-द्‌सि
-द्‍सि
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
deleted file mode 100644
index 4a8326c23..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-क
-क़
-कि
-क्
-क्क
-क्र
-क्र्क
-क्र्‍
-क्ष
-क्ष्
-क्‌ष
-क्‍
-क्‍ष
-छ्र्क
-ज्ञ्
-ट्रु
-र्क
-र्कि
-र्क्रि
-र्‍
-ि
-फ़्र
-फ्र
-द्दि
-क्ष
-क्‌ष
-क्‍ष
-र्अ्
-र्अ्‌
-र्अ्‍
-र्आ्र्
-क‌ि
-ऽं
-रुँः
-1ि
-१॑
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt
deleted file mode 100644
index 481401983..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt
+++ /dev/null
@@ -1 +0,0 @@
-सा़े
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt
deleted file mode 100644
index 1723ced84..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Usage:
- ./hb-unicode-encode UNICODE_STRING...
-or:
- ./hb-unicode-encode --stdin
-फि्
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644
index 89cefb6d9..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-क़
-ख़
-ग़
-ज़
-ड़
-ढ़
-फ़
-य
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index 9f7cda9c1..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ॠ
-ॡ
-ॢ
-ॣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 3aa66ceae..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-क
-ख
-ग
-घ
-ङ
-च
-छ
-ज
-झ
-ञ
-ट
-ठ
-ड
-ढ
-ण
-त
-थ
-द
-ध
-न
-ऩ
-प
-फ
-ब
-भ
-म
-य
-र
-ऱ
-ल
-ळ
-ऴ
-व
-श
-ष
-स
-ह
-क़
-ख़
-ग़
-ज़
-ड़
-ढ़
-फ़
-य़
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index 04cf0a711..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-ा
-ि
-ी
-ु
-ू
-ृ
-ॄ
-ॅ
-ॆ
-े
-ै
-ॉ
-ो
-ौ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
deleted file mode 100644
index 7b0b32cbf..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
+++ /dev/null
@@ -1 +0,0 @@
-॰
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 142700284..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-०
-१
-२
-३
-४
-५
-६
-७
-८
-९
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index b336c3597..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-अ
-आ
-इ
-ई
-उ
-ऊ
-ऋ
-ऌ
-ऍ
-ऎ
-ए
-ऐ
-ऑ
-ऒ
-ओ
-औ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 2ff3e878a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-ँ
-ं
-ः
-़
-ऽ
-्
-ॐ
-॒
-॓
-॔
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 6d573083a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,185 +0,0 @@
-कॅ
-खॅ
-गॅ
-घॅ
-ङॅ
-चॅ
-छॅ
-जॅ
-झॅ
-ञॅ
-टॅ
-ठॅ
-डॅ
-ढॅ
-णॅ
-तॅ
-थॅ
-दॅ
-धॅ
-नॅ
-ऩॅ
-पॅ
-फॅ
-बॅ
-भॅ
-मॅ
-यॅ
-रॅ
-ऱॅ
-लॅ
-ळॅ
-ऴॅ
-वॅ
-शॅ
-षॅ
-सॅ
-हॅ
-कॆ
-खॆ
-गॆ
-घॆ
-ङॆ
-चॆ
-छॆ
-जॆ
-झॆ
-ञॆ
-टॆ
-ठॆ
-डॆ
-ढॆ
-णॆ
-तॆ
-थॆ
-दॆ
-धॆ
-नॆ
-ऩॆ
-पॆ
-फॆ
-बॆ
-भॆ
-मॆ
-यॆ
-रॆ
-ऱॆ
-लॆ
-ळॆ
-ऴॆ
-वॆ
-शॆ
-षॆ
-सॆ
-हॆ
-के
-खे
-गे
-घे
-ङे
-चे
-छे
-जे
-झे
-ञे
-टे
-ठे
-डे
-ढे
-णे
-ते
-थे
-दे
-धे
-ने
-ऩे
-पे
-फे
-बे
-भे
-मे
-ये
-रे
-ऱे
-ले
-ळे
-ऴे
-वे
-शे
-षे
-से
-हे
-कै
-खै
-गै
-घै
-ङै
-चै
-छै
-जै
-झै
-ञै
-टै
-ठै
-डै
-ढै
-णै
-तै
-थै
-दै
-धै
-नै
-ऩै
-पै
-फै
-बै
-भै
-मै
-यै
-रै
-ऱै
-लै
-ळै
-ऴै
-वै
-शै
-षै
-सै
-है
-कँ
-खँ
-गँ
-घँ
-ङँ
-चँ
-छँ
-जँ
-झँ
-ञँ
-टँ
-ठँ
-डँ
-ढँ
-णँ
-तँ
-थँ
-दँ
-धँ
-नँ
-ऩँ
-पँ
-फँ
-बँ
-भँ
-मँ
-यँ
-रँ
-ऱँ
-लँ
-ळँ
-ऴँ
-वँ
-शँ
-षँ
-सँ
-हँ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index bff1a7b86..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,185 +0,0 @@
-कु
-खु
-गु
-घु
-ङु
-चु
-छु
-जु
-झु
-ञु
-टु
-ठु
-डु
-ढु
-णु
-तु
-थु
-दु
-धु
-नु
-ऩु
-पु
-फु
-बु
-भु
-मु
-यु
-रु
-ऱु
-लु
-ळु
-ऴु
-वु
-शु
-षु
-सु
-हु
-कू
-खू
-गू
-घू
-ङू
-चू
-छू
-जू
-झू
-ञू
-टू
-ठू
-डू
-ढू
-णू
-तू
-थू
-दू
-धू
-नू
-ऩू
-पू
-फू
-बू
-भू
-मू
-यू
-रू
-ऱू
-लू
-ळू
-ऴू
-वू
-शू
-षू
-सू
-हू
-कृ
-खृ
-गृ
-घृ
-ङृ
-चृ
-छृ
-जृ
-झृ
-ञृ
-टृ
-ठृ
-डृ
-ढृ
-णृ
-तृ
-थृ
-दृ
-धृ
-नृ
-ऩृ
-पृ
-फृ
-बृ
-भृ
-मृ
-यृ
-रृ
-ऱृ
-लृ
-ळृ
-ऴृ
-वृ
-शृ
-षृ
-सृ
-हृ
-कॄ
-खॄ
-गॄ
-घॄ
-ङॄ
-चॄ
-छॄ
-जॄ
-झॄ
-ञॄ
-टॄ
-ठॄ
-डॄ
-ढॄ
-णॄ
-तॄ
-थॄ
-दॄ
-धॄ
-नॄ
-ऩॄ
-पॄ
-फॄ
-बॄ
-भॄ
-मॄ
-यॄ
-रॄ
-ऱॄ
-लॄ
-ळॄ
-ऴॄ
-वॄ
-शॄ
-षॄ
-सॄ
-हॄ
-क्
-ख्
-ग्
-घ्
-ङ्
-च्
-छ्
-ज्
-झ्
-ञ्
-ट्
-ठ्
-ड्
-ढ्
-ण्
-त्
-थ्
-द्
-ध्
-न्
-ऩ्
-प्
-फ्
-ब्
-भ्
-म्
-य्
-र्
-ऱ्
-ल्
-ळ्
-ऴ्
-व्
-श्
-ष्
-स्
-ह्
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 3b5e620c9..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,1367 +0,0 @@
-क्क
-क्ख
-क्ग
-क्घ
-क्ङ
-क्च
-क्छ
-क्ज
-क्झ
-क्ञ
-क्ट
-क्ठ
-क्ड
-क्ढ
-क्ण
-क्त
-क्थ
-क्द
-क्ध
-क्न
-क्ऩ
-क्प
-क्फ
-क्ब
-क्भ
-क्म
-क्य
-क्र
-क्ऱ
-क्ल
-क्ळ
-क्ऴ
-क्व
-क्श
-क्ष
-क्स
-क्ह
-ख्क
-ख्ख
-ख्ग
-ख्घ
-ख्ङ
-ख्च
-ख्छ
-ख्ज
-ख्झ
-ख्ञ
-ख्ट
-ख्ठ
-ख्ड
-ख्ढ
-ख्ण
-ख्त
-ख्थ
-ख्द
-ख्ध
-ख्न
-ख्ऩ
-ख्प
-ख्फ
-ख्ब
-ख्भ
-ख्म
-ख्य
-ख्र
-ख्ऱ
-ख्ल
-ख्ळ
-ख्ऴ
-ख्व
-ख्श
-ख्ष
-ख्स
-ख्ह
-ग्क
-ग्ख
-ग्ग
-ग्घ
-ग्ङ
-ग्च
-ग्छ
-ग्ज
-ग्झ
-ग्ञ
-ग्ट
-ग्ठ
-ग्ड
-ग्ढ
-ग्ण
-ग्त
-ग्थ
-ग्द
-ग्ध
-ग्न
-ग्ऩ
-ग्प
-ग्फ
-ग्ब
-ग्भ
-ग्म
-ग्य
-ग्र
-ग्ऱ
-ग्ल
-ग्ळ
-ग्ऴ
-ग्व
-ग्श
-ग्ष
-ग्स
-ग्ह
-घ्क
-घ्ख
-घ्ग
-घ्घ
-घ्ङ
-घ्च
-घ्छ
-घ्ज
-घ्झ
-घ्ञ
-घ्ट
-घ्ठ
-घ्ड
-घ्ढ
-घ्ण
-घ्त
-घ्थ
-घ्द
-घ्ध
-घ्न
-घ्ऩ
-घ्प
-घ्फ
-घ्ब
-घ्भ
-घ्म
-घ्य
-घ्र
-घ्ऱ
-घ्ल
-घ्ळ
-घ्ऴ
-घ्व
-घ्श
-घ्ष
-घ्स
-घ्ह
-ङ्क
-ङ्ख
-ङ्ग
-ङ्घ
-ङ्ङ
-ङ्च
-ङ्छ
-ङ्ज
-ङ्झ
-ङ्ञ
-ङ्ट
-ङ्ठ
-ङ्ड
-ङ्ढ
-ङ्ण
-ङ्त
-ङ्थ
-ङ्द
-ङ्ध
-ङ्न
-ङ्ऩ
-ङ्प
-ङ्फ
-ङ्ब
-ङ्भ
-ङ्म
-ङ्य
-ङ्र
-ङ्ऱ
-ङ्ल
-ङ्ळ
-ङ्ऴ
-ङ्व
-ङ्श
-ङ्ष
-ङ्स
-ङ्ह
-च्क
-च्ख
-च्ग
-च्घ
-च्ङ
-च्च
-च्छ
-च्ज
-च्झ
-च्ञ
-च्ट
-च्ठ
-च्ड
-च्ढ
-च्ण
-च्त
-च्थ
-च्द
-च्ध
-च्न
-च्ऩ
-च्प
-च्फ
-च्ब
-च्भ
-च्म
-च्य
-च्र
-च्ऱ
-च्ल
-च्ळ
-च्ऴ
-च्व
-च्श
-च्ष
-च्स
-च्ह
-छ्क
-छ्ख
-छ्ग
-छ्घ
-छ्ङ
-छ्च
-छ्छ
-छ्ज
-छ्झ
-छ्ञ
-छ्ट
-छ्ठ
-छ्ड
-छ्ढ
-छ्ण
-छ्त
-छ्थ
-छ्द
-छ्ध
-छ्न
-छ्ऩ
-छ्प
-छ्फ
-छ्ब
-छ्भ
-छ्म
-छ्य
-छ्र
-छ्ऱ
-छ्ल
-छ्ळ
-छ्ऴ
-छ्व
-छ्श
-छ्ष
-छ्स
-छ्ह
-ज्क
-ज्ख
-ज्ग
-ज्घ
-ज्ङ
-ज्च
-ज्छ
-ज्ज
-ज्झ
-ज्ञ
-ज्ट
-ज्ठ
-ज्ड
-ज्ढ
-ज्ण
-ज्त
-ज्थ
-ज्द
-ज्ध
-ज्न
-ज्ऩ
-ज्प
-ज्फ
-ज्ब
-ज्भ
-ज्म
-ज्य
-ज्र
-ज्ऱ
-ज्ल
-ज्ळ
-ज्ऴ
-ज्व
-ज्श
-ज्ष
-ज्स
-ज्ह
-झ्क
-झ्ख
-झ्ग
-झ्घ
-झ्ङ
-झ्च
-झ्छ
-झ्ज
-झ्झ
-झ्ञ
-झ्ट
-झ्ठ
-झ्ड
-झ्ढ
-झ्ण
-झ्त
-झ्थ
-झ्द
-झ्ध
-झ्न
-झ्ऩ
-झ्प
-झ्फ
-झ्ब
-झ्भ
-झ्म
-झ्य
-झ्र
-झ्ऱ
-झ्ल
-झ्ळ
-झ्ऴ
-झ्व
-झ्श
-झ्ष
-झ्स
-झ्ह
-ञ्क
-ञ्ख
-ञ्ग
-ञ्घ
-ञ्ङ
-ञ्च
-ञ्छ
-ञ्ज
-ञ्झ
-ञ्ञ
-ञ्ट
-ञ्ठ
-ञ्ड
-ञ्ढ
-ञ्ण
-ञ्त
-ञ्थ
-ञ्द
-ञ्ध
-ञ्न
-ञ्ऩ
-ञ्प
-ञ्फ
-ञ्ब
-ञ्भ
-ञ्म
-ञ्य
-ञ्र
-ञ्ऱ
-ञ्ल
-ञ्ळ
-ञ्ऴ
-ञ्व
-ञ्श
-ञ्ष
-ञ्स
-ञ्ह
-ट्क
-ट्ख
-ट्ग
-ट्घ
-ट्ङ
-ट्च
-ट्छ
-ट्ज
-ट्झ
-ट्ञ
-ट्ट
-ट्ठ
-ट्ड
-ट्ढ
-ट्ण
-ट्त
-ट्थ
-ट्द
-ट्ध
-ट्न
-ट्ऩ
-ट्प
-ट्फ
-ट्ब
-ट्भ
-ट्म
-ट्य
-ट्र
-ट्ऱ
-ट्ल
-ट्ळ
-ट्ऴ
-ट्व
-ट्श
-ट्ष
-ट्स
-ट्ह
-ठ्क
-ठ्ख
-ठ्ग
-ठ्घ
-ठ्ङ
-ठ्च
-ठ्छ
-ठ्ज
-ठ्झ
-ठ्ञ
-ठ्ट
-ठ्ठ
-ठ्ड
-ठ्ढ
-ठ्ण
-ठ्त
-ठ्थ
-ठ्द
-ठ्ध
-ठ्न
-ठ्ऩ
-ठ्प
-ठ्फ
-ठ्ब
-ठ्भ
-ठ्म
-ठ्य
-ठ्र
-ठ्ऱ
-ठ्ल
-ठ्ळ
-ठ्ऴ
-ठ्व
-ठ्श
-ठ्ष
-ठ्स
-ठ्ह
-ड्क
-ड्ख
-ड्ग
-ड्घ
-ड्ङ
-ड्च
-ड्छ
-ड्ज
-ड्झ
-ड्ञ
-ड्ट
-ड्ठ
-ड्ड
-ड्ढ
-ड्ण
-ड्त
-ड्थ
-ड्द
-ड्ध
-ड्न
-ड्ऩ
-ड्प
-ड्फ
-ड्ब
-ड्भ
-ड्म
-ड्य
-ड्र
-ड्ऱ
-ड्ल
-ड्ळ
-ड्ऴ
-ड्व
-ड्श
-ड्ष
-ड्स
-ड्ह
-ढ्क
-ढ्ख
-ढ्ग
-ढ्घ
-ढ्ङ
-ढ्च
-ढ्छ
-ढ्ज
-ढ्झ
-ढ्ञ
-ढ्ट
-ढ्ठ
-ढ्ड
-ढ्ढ
-ढ्ण
-ढ्त
-ढ्थ
-ढ्द
-ढ्ध
-ढ्न
-ढ्ऩ
-ढ्प
-ढ्फ
-ढ्ब
-ढ्भ
-ढ्म
-ढ्य
-ढ्र
-ढ्ऱ
-ढ्ल
-ढ्ळ
-ढ्ऴ
-ढ्व
-ढ्श
-ढ्ष
-ढ्स
-ढ्ह
-ण्क
-ण्ख
-ण्ग
-ण्घ
-ण्ङ
-ण्च
-ण्छ
-ण्ज
-ण्झ
-ण्ञ
-ण्ट
-ण्ठ
-ण्ड
-ण्ढ
-ण्ण
-ण्त
-ण्थ
-ण्द
-ण्ध
-ण्न
-ण्ऩ
-ण्प
-ण्फ
-ण्ब
-ण्भ
-ण्म
-ण्य
-ण्र
-ण्ऱ
-ण्ल
-ण्ळ
-ण्ऴ
-ण्व
-ण्श
-ण्ष
-ण्स
-ण्ह
-त्क
-त्ख
-त्ग
-त्घ
-त्ङ
-त्च
-त्छ
-त्ज
-त्झ
-त्ञ
-त्ट
-त्ठ
-त्ड
-त्ढ
-त्ण
-त्त
-त्थ
-त्द
-त्ध
-त्न
-त्ऩ
-त्प
-त्फ
-त्ब
-त्भ
-त्म
-त्य
-त्र
-त्ऱ
-त्ल
-त्ळ
-त्ऴ
-त्व
-त्श
-त्ष
-त्स
-त्ह
-थ्क
-थ्ख
-थ्ग
-थ्घ
-थ्ङ
-थ्च
-थ्छ
-थ्ज
-थ्झ
-थ्ञ
-थ्ट
-थ्ठ
-थ्ड
-थ्ढ
-थ्ण
-थ्त
-थ्थ
-थ्द
-थ्ध
-थ्न
-थ्ऩ
-थ्प
-थ्फ
-थ्ब
-थ्भ
-थ्म
-थ्य
-थ्र
-थ्ऱ
-थ्ल
-थ्ळ
-थ्ऴ
-थ्व
-थ्श
-थ्ष
-थ्स
-थ्ह
-द्क
-द्ख
-द्ग
-द्घ
-द्ङ
-द्च
-द्छ
-द्ज
-द्झ
-द्ञ
-द्ट
-द्ठ
-द्ड
-द्ढ
-द्ण
-द्त
-द्थ
-द्द
-द्ध
-द्न
-द्ऩ
-द्प
-द्फ
-द्ब
-द्भ
-द्म
-द्य
-द्र
-द्ऱ
-द्ल
-द्ळ
-द्ऴ
-द्व
-द्श
-द्ष
-द्स
-द्ह
-ध्क
-ध्ख
-ध्ग
-ध्घ
-ध्ङ
-ध्च
-ध्छ
-ध्ज
-ध्झ
-ध्ञ
-ध्ट
-ध्ठ
-ध्ड
-ध्ढ
-ध्ण
-ध्त
-ध्थ
-ध्द
-ध्ध
-ध्न
-ध्ऩ
-ध्प
-ध्फ
-ध्ब
-ध्भ
-ध्म
-ध्य
-ध्र
-ध्ऱ
-ध्ल
-ध्ळ
-ध्ऴ
-ध्व
-ध्श
-ध्ष
-ध्स
-ध्ह
-न्क
-न्ख
-न्ग
-न्घ
-न्ङ
-न्च
-न्छ
-न्ज
-न्झ
-न्ञ
-न्ट
-न्ठ
-न्ड
-न्ढ
-न्ण
-न्त
-न्थ
-न्द
-न्ध
-न्न
-न्ऩ
-न्प
-न्फ
-न्ब
-न्भ
-न्म
-न्य
-न्र
-न्ऱ
-न्ल
-न्ळ
-न्ऴ
-न्व
-न्श
-न्ष
-न्स
-न्ह
-ऩ्क
-ऩ्ख
-ऩ्ग
-ऩ्घ
-ऩ्ङ
-ऩ्च
-ऩ्छ
-ऩ्ज
-ऩ्झ
-ऩ्ञ
-ऩ्ट
-ऩ्ठ
-ऩ्ड
-ऩ्ढ
-ऩ्ण
-ऩ्त
-ऩ्थ
-ऩ्द
-ऩ्ध
-ऩ्न
-ऩ्ऩ
-ऩ्प
-ऩ्फ
-ऩ्ब
-ऩ्भ
-ऩ्म
-ऩ्य
-ऩ्र
-ऩ्ऱ
-ऩ्ल
-ऩ्ळ
-ऩ्ऴ
-ऩ्व
-ऩ्श
-ऩ्ष
-ऩ्स
-ऩ्ह
-प्क
-प्ख
-प्ग
-प्घ
-प्ङ
-प्च
-प्छ
-प्ज
-प्झ
-प्ञ
-प्ट
-प्ठ
-प्ड
-प्ढ
-प्ण
-प्त
-प्थ
-प्द
-प्ध
-प्न
-प्ऩ
-प्प
-प्फ
-प्ब
-प्भ
-प्म
-प्य
-प्र
-प्ऱ
-प्ल
-प्ळ
-प्ऴ
-प्व
-प्श
-प्ष
-प्स
-प्ह
-फ्क
-फ्ख
-फ्ग
-फ्घ
-फ्ङ
-फ्च
-फ्छ
-फ्ज
-फ्झ
-फ्ञ
-फ्ट
-फ्ठ
-फ्ड
-फ्ढ
-फ्ण
-फ्त
-फ्थ
-फ्द
-फ्ध
-फ्न
-फ्ऩ
-फ्प
-फ्फ
-फ्ब
-फ्भ
-फ्म
-फ्य
-फ्र
-फ्ऱ
-फ्ल
-फ्ळ
-फ्ऴ
-फ्व
-फ्श
-फ्ष
-फ्स
-फ्ह
-ब्क
-ब्ख
-ब्ग
-ब्घ
-ब्ङ
-ब्च
-ब्छ
-ब्ज
-ब्झ
-ब्ञ
-ब्ट
-ब्ठ
-ब्ड
-ब्ढ
-ब्ण
-ब्त
-ब्थ
-ब्द
-ब्ध
-ब्न
-ब्ऩ
-ब्प
-ब्फ
-ब्ब
-ब्भ
-ब्म
-ब्य
-ब्र
-ब्ऱ
-ब्ल
-ब्ळ
-ब्ऴ
-ब्व
-ब्श
-ब्ष
-ब्स
-ब्ह
-भ्क
-भ्ख
-भ्ग
-भ्घ
-भ्ङ
-भ्च
-भ्छ
-भ्ज
-भ्झ
-भ्ञ
-भ्ट
-भ्ठ
-भ्ड
-भ्ढ
-भ्ण
-भ्त
-भ्थ
-भ्द
-भ्ध
-भ्न
-भ्ऩ
-भ्प
-भ्फ
-भ्ब
-भ्भ
-भ्म
-भ्य
-भ्र
-भ्ऱ
-भ्ल
-भ्ळ
-भ्ऴ
-भ्व
-भ्श
-भ्ष
-भ्स
-भ्ह
-म्क
-म्ख
-म्ग
-म्घ
-म्ङ
-म्च
-म्छ
-म्ज
-म्झ
-म्ञ
-म्ट
-म्ठ
-म्ड
-म्ढ
-म्ण
-म्त
-म्थ
-म्द
-म्ध
-म्न
-म्ऩ
-म्प
-म्फ
-म्ब
-म्भ
-म्म
-म्य
-म्र
-म्ऱ
-म्ल
-म्ळ
-म्ऴ
-म्व
-म्श
-म्ष
-म्स
-म्ह
-य्क
-य्ख
-य्ग
-य्घ
-य्ङ
-य्च
-य्छ
-य्ज
-य्झ
-य्ञ
-य्ट
-य्ठ
-य्ड
-य्ढ
-य्ण
-य्त
-य्थ
-य्द
-य्ध
-य्न
-य्ऩ
-य्प
-य्फ
-य्ब
-य्भ
-य्म
-य्य
-य्र
-य्ऱ
-य्ल
-य्ळ
-य्ऴ
-य्व
-य्श
-य्ष
-य्स
-य्ह
-र्क
-र्ख
-र्ग
-र्घ
-र्ङ
-र्च
-र्छ
-र्ज
-र्झ
-र्ञ
-र्ट
-र्ठ
-र्ड
-र्ढ
-र्ण
-र्त
-र्थ
-र्द
-र्ध
-र्न
-र्ऩ
-र्प
-र्फ
-र्ब
-र्भ
-र्म
-र्य
-र्र
-र्ऱ
-र्ल
-र्ळ
-र्ऴ
-र्व
-र्श
-र्ष
-र्स
-र्ह
-ऱ्क
-ऱ्ख
-ऱ्ग
-ऱ्घ
-ऱ्ङ
-ऱ्च
-ऱ्छ
-ऱ्ज
-ऱ्झ
-ऱ्ञ
-ऱ्ट
-ऱ्ठ
-ऱ्ड
-ऱ्ढ
-ऱ्ण
-ऱ्त
-ऱ्थ
-ऱ्द
-ऱ्ध
-ऱ्न
-ऱ्ऩ
-ऱ्प
-ऱ्फ
-ऱ्ब
-ऱ्भ
-ऱ्म
-ऱ्य
-ऱ्र
-ऱ्ऱ
-ऱ्ल
-ऱ्ळ
-ऱ्ऴ
-ऱ्व
-ऱ्श
-ऱ्ष
-ऱ्स
-ऱ्ह
-ल्क
-ल्ख
-ल्ग
-ल्घ
-ल्ङ
-ल्च
-ल्छ
-ल्ज
-ल्झ
-ल्ञ
-ल्ट
-ल्ठ
-ल्ड
-ल्ढ
-ल्ण
-ल्त
-ल्थ
-ल्द
-ल्ध
-ल्न
-ल्ऩ
-ल्प
-ल्फ
-ल्ब
-ल्भ
-ल्म
-ल्य
-ल्र
-ल्ऱ
-ल्ल
-ल्ळ
-ल्ऴ
-ल्व
-ल्श
-ल्ष
-ल्स
-ल्ह
-ळ्क
-ळ्ख
-ळ्ग
-ळ्घ
-ळ्ङ
-ळ्च
-ळ्छ
-ळ्ज
-ळ्झ
-ळ्ञ
-ळ्ट
-ळ्ठ
-ळ्ड
-ळ्ढ
-ळ्ण
-ळ्त
-ळ्थ
-ळ्द
-ळ्ध
-ळ्न
-ळ्ऩ
-ळ्प
-ळ्फ
-ळ्ब
-ळ्भ
-ळ्म
-ळ्य
-ळ्र
-ळ्ऱ
-ळ्ल
-ळ्ळ
-ळ्ऴ
-ळ्व
-ळ्श
-ळ्ष
-ळ्स
-ळ्ह
-ऴ्क
-ऴ्ख
-ऴ्ग
-ऴ्घ
-ऴ्ङ
-ऴ्च
-ऴ्छ
-ऴ्ज
-ऴ्झ
-ऴ्ञ
-ऴ्ट
-ऴ्ठ
-ऴ्ड
-ऴ्ढ
-ऴ्ण
-ऴ्त
-ऴ्थ
-ऴ्द
-ऴ्ध
-ऴ्न
-ऴ्ऩ
-ऴ्प
-ऴ्फ
-ऴ्ब
-ऴ्भ
-ऴ्म
-ऴ्य
-ऴ्र
-ऴ्ऱ
-ऴ्ल
-ऴ्ळ
-ऴ्ऴ
-ऴ्व
-ऴ्श
-ऴ्ष
-ऴ्स
-ऴ्ह
-व्क
-व्ख
-व्ग
-व्घ
-व्ङ
-व्च
-व्छ
-व्ज
-व्झ
-व्ञ
-व्ट
-व्ठ
-व्ड
-व्ढ
-व्ण
-व्त
-व्थ
-व्द
-व्ध
-व्न
-व्ऩ
-व्प
-व्फ
-व्ब
-व्भ
-व्म
-व्य
-व्र
-व्ऱ
-व्ल
-व्ळ
-व्ऴ
-व्व
-व्श
-व्ष
-व्स
-व्ह
-श्क
-श्ख
-श्ग
-श्घ
-श्ङ
-श्च
-श्छ
-श्ज
-श्झ
-श्ञ
-श्ट
-श्ठ
-श्ड
-श्ढ
-श्ण
-श्त
-श्थ
-श्द
-श्ध
-श्न
-श्ऩ
-श्प
-श्फ
-श्ब
-श्भ
-श्म
-श्य
-श्र
-श्ऱ
-श्ल
-श्ळ
-श्ऴ
-श्व
-श्श
-श्ष
-श्स
-श्ह
-ष्क
-ष्ख
-ष्ग
-ष्घ
-ष्ङ
-ष्च
-ष्छ
-ष्ज
-ष्झ
-ष्ञ
-ष्ट
-ष्ठ
-ष्ड
-ष्ढ
-ष्ण
-ष्त
-ष्थ
-ष्द
-ष्ध
-ष्न
-ष्ऩ
-ष्प
-ष्फ
-ष्ब
-ष्भ
-ष्म
-ष्य
-ष्र
-ष्ऱ
-ष्ल
-ष्ळ
-ष्ऴ
-ष्व
-ष्श
-ष्ष
-ष्स
-ष्ह
-स्क
-स्ख
-स्ग
-स्घ
-स्ङ
-स्च
-स्छ
-स्ज
-स्झ
-स्ञ
-स्ट
-स्ठ
-स्ड
-स्ढ
-स्ण
-स्त
-स्थ
-स्द
-स्ध
-स्न
-स्ऩ
-स्प
-स्फ
-स्ब
-स्भ
-स्म
-स्य
-स्र
-स्ऱ
-स्ल
-स्ळ
-स्ऴ
-स्व
-स्श
-स्ष
-स्स
-स्ह
-ह्क
-ह्ख
-ह्ग
-ह्घ
-ह्ङ
-ह्च
-ह्छ
-ह्ज
-ह्झ
-ह्ञ
-ह्ट
-ह्ठ
-ह्ड
-ह्ढ
-ह्ण
-ह्त
-ह्थ
-ह्द
-ह्ध
-ह्न
-ह्ऩ
-ह्प
-ह्फ
-ह्ब
-ह्भ
-ह्म
-ह्य
-ह्र
-ह्ऱ
-ह्ल
-ह्ळ
-ह्ऴ
-ह्व
-ह्श
-ह्ष
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
deleted file mode 100644
index add4332b3..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-આ અા
-ઍ અૅ
-એ અે
-ઐ અૈ
-ઑ અૉ
-ઓ અો અાૅ
-ઔ અૌ અાૈ
-ૉ ૅા
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index fd5e6e68b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index e91003ab9..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-ક
-ખ
-ગ
-ઘ
-ઙ
-ચ
-છ
-જ
-ઝ
-ઞ
-ટ
-ઠ
-ડ
-ઢ
-ણ
-ત
-થ
-દ
-ધ
-ન
-પ
-ફ
-બ
-ભ
-મ
-ય
-ર
-લ
-ળ
-વ
-શ
-ષ
-સ
-હ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index 36502985f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-ા
-િ
-ી
-ુ
-ૂ
-ૃ
-ૅ
-ે
-ૈ
-ૉ
-ો
-ૌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index eabae3979..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-૦
-૧
-૨
-૩
-૪
-૫
-૬
-૭
-૮
-૯
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 116eb6067..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-અ
-આ
-ઇ
-ઈ
-ઉ
-ઊ
-ઋ
-ઍ
-એ
-ઐ
-ઑ
-ઓ
-ઔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 218e5070c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-ઁ
-ં
-ઃ
-઼
-ઽ
-્
-ૐ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index f7ff3af9e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,170 +0,0 @@
-કૅ
-ખૅ
-ગૅ
-ઘૅ
-ઙૅ
-ચૅ
-છૅ
-જૅ
-ઝૅ
-ઞૅ
-ટૅ
-ઠૅ
-ડૅ
-ઢૅ
-ણૅ
-તૅ
-થૅ
-દૅ
-ધૅ
-નૅ
-પૅ
-ફૅ
-બૅ
-ભૅ
-મૅ
-યૅ
-રૅ
-લૅ
-ળૅ
-વૅ
-શૅ
-ષૅ
-સૅ
-હૅ
-કે
-ખે
-ગે
-ઘે
-ઙે
-ચે
-છે
-જે
-ઝે
-ઞે
-ટે
-ઠે
-ડે
-ઢે
-ણે
-તે
-થે
-દે
-ધે
-ને
-પે
-ફે
-બે
-ભે
-મે
-યે
-રે
-લે
-ળે
-વે
-શે
-ષે
-સે
-હે
-કૈ
-ખૈ
-ગૈ
-ઘૈ
-ઙૈ
-ચૈ
-છૈ
-જૈ
-ઝૈ
-ઞૈ
-ટૈ
-ઠૈ
-ડૈ
-ઢૈ
-ણૈ
-તૈ
-થૈ
-દૈ
-ધૈ
-નૈ
-પૈ
-ફૈ
-બૈ
-ભૈ
-મૈ
-યૈ
-રૈ
-લૈ
-ળૈ
-વૈ
-શૈ
-ષૈ
-સૈ
-હૈ
-કઁ
-ખઁ
-ગઁ
-ઘઁ
-ઙઁ
-ચઁ
-છઁ
-જઁ
-ઝઁ
-ઞઁ
-ટઁ
-ઠઁ
-ડઁ
-ઢઁ
-ણઁ
-તઁ
-થઁ
-દઁ
-ધઁ
-નઁ
-પઁ
-ફઁ
-બઁ
-ભઁ
-મઁ
-યઁ
-રઁ
-લઁ
-ળઁ
-વઁ
-શઁ
-ષઁ
-સઁ
-હઁ
-કં
-ખં
-ગં
-ઘં
-ઙં
-ચં
-છં
-જં
-ઝં
-ઞં
-ટં
-ઠં
-ડં
-ઢં
-ણં
-તં
-થં
-દં
-ધં
-નં
-પં
-ફં
-બં
-ભં
-મં
-યં
-રં
-લં
-ળં
-વં
-શં
-ષં
-સં
-હં
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index fa658cfba..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,170 +0,0 @@
-કુ
-ખુ
-ગુ
-ઘુ
-ઙુ
-ચુ
-છુ
-જુ
-ઝુ
-ઞુ
-ટુ
-ઠુ
-ડુ
-ઢુ
-ણુ
-તુ
-થુ
-દુ
-ધુ
-નુ
-પુ
-ફુ
-બુ
-ભુ
-મુ
-યુ
-રુ
-લુ
-ળુ
-વુ
-શુ
-ષુ
-સુ
-હુ
-કૂ
-ખૂ
-ગૂ
-ઘૂ
-ઙૂ
-ચૂ
-છૂ
-જૂ
-ઝૂ
-ઞૂ
-ટૂ
-ઠૂ
-ડૂ
-ઢૂ
-ણૂ
-તૂ
-થૂ
-દૂ
-ધૂ
-નૂ
-પૂ
-ફૂ
-બૂ
-ભૂ
-મૂ
-યૂ
-રૂ
-લૂ
-ળૂ
-વૂ
-શૂ
-ષૂ
-સૂ
-હૂ
-કૃ
-ખૃ
-ગૃ
-ઘૃ
-ઙૃ
-ચૃ
-છૃ
-જૃ
-ઝૃ
-ઞૃ
-ટૃ
-ઠૃ
-ડૃ
-ઢૃ
-ણૃ
-તૃ
-થૃ
-દૃ
-ધૃ
-નૃ
-પૃ
-ફૃ
-બૃ
-ભૃ
-મૃ
-યૃ
-રૃ
-લૃ
-ળૃ
-વૃ
-શૃ
-ષૃ
-સૃ
-હૃ
-કૄ
-ખૄ
-ગૄ
-ઘૄ
-ઙૄ
-ચૄ
-છૄ
-જૄ
-ઝૄ
-ઞૄ
-ટૄ
-ઠૄ
-ડૄ
-ઢૄ
-ણૄ
-તૄ
-થૄ
-દૄ
-ધૄ
-નૄ
-પૄ
-ફૄ
-બૄ
-ભૄ
-મૄ
-યૄ
-રૄ
-લૄ
-ળૄ
-વૄ
-શૄ
-ષૄ
-સૄ
-હૄ
-ક્
-ખ્
-ગ્
-ઘ્
-ઙ્
-ચ્
-છ્
-જ્
-ઝ્
-ઞ્
-ટ્
-ઠ્
-ડ્
-ઢ્
-ણ્
-ત્
-થ્
-દ્
-ધ્
-ન્
-પ્
-ફ્
-બ્
-ભ્
-મ્
-ય્
-ર્
-લ્
-ળ્
-વ્
-શ્
-ષ્
-સ્
-હ્
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 6211c9b41..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,1156 +0,0 @@
-ક્ક
-ક્ખ
-ક્ગ
-ક્ઘ
-ક્ઙ
-ક્ચ
-ક્છ
-ક્જ
-ક્ઝ
-ક્ઞ
-ક્ટ
-ક્ઠ
-ક્ડ
-ક્ઢ
-ક્ણ
-ક્ત
-ક્થ
-ક્દ
-ક્ધ
-ક્ન
-ક્પ
-ક્ફ
-ક્બ
-ક્ભ
-ક્મ
-ક્ય
-ક્ર
-ક્લ
-ક્ળ
-ક્વ
-ક્શ
-ક્ષ
-ક્સ
-ક્હ
-ખ્ક
-ખ્ખ
-ખ્ગ
-ખ્ઘ
-ખ્ઙ
-ખ્ચ
-ખ્છ
-ખ્જ
-ખ્ઝ
-ખ્ઞ
-ખ્ટ
-ખ્ઠ
-ખ્ડ
-ખ્ઢ
-ખ્ણ
-ખ્ત
-ખ્થ
-ખ્દ
-ખ્ધ
-ખ્ન
-ખ્પ
-ખ્ફ
-ખ્બ
-ખ્ભ
-ખ્મ
-ખ્ય
-ખ્ર
-ખ્લ
-ખ્ળ
-ખ્વ
-ખ્શ
-ખ્ષ
-ખ્સ
-ખ્હ
-ગ્ક
-ગ્ખ
-ગ્ગ
-ગ્ઘ
-ગ્ઙ
-ગ્ચ
-ગ્છ
-ગ્જ
-ગ્ઝ
-ગ્ઞ
-ગ્ટ
-ગ્ઠ
-ગ્ડ
-ગ્ઢ
-ગ્ણ
-ગ્ત
-ગ્થ
-ગ્દ
-ગ્ધ
-ગ્ન
-ગ્પ
-ગ્ફ
-ગ્બ
-ગ્ભ
-ગ્મ
-ગ્ય
-ગ્ર
-ગ્લ
-ગ્ળ
-ગ્વ
-ગ્શ
-ગ્ષ
-ગ્સ
-ગ્હ
-ઘ્ક
-ઘ્ખ
-ઘ્ગ
-ઘ્ઘ
-ઘ્ઙ
-ઘ્ચ
-ઘ્છ
-ઘ્જ
-ઘ્ઝ
-ઘ્ઞ
-ઘ્ટ
-ઘ્ઠ
-ઘ્ડ
-ઘ્ઢ
-ઘ્ણ
-ઘ્ત
-ઘ્થ
-ઘ્દ
-ઘ્ધ
-ઘ્ન
-ઘ્પ
-ઘ્ફ
-ઘ્બ
-ઘ્ભ
-ઘ્મ
-ઘ્ય
-ઘ્ર
-ઘ્લ
-ઘ્ળ
-ઘ્વ
-ઘ્શ
-ઘ્ષ
-ઘ્સ
-ઘ્હ
-ઙ્ક
-ઙ્ખ
-ઙ્ગ
-ઙ્ઘ
-ઙ્ઙ
-ઙ્ચ
-ઙ્છ
-ઙ્જ
-ઙ્ઝ
-ઙ્ઞ
-ઙ્ટ
-ઙ્ઠ
-ઙ્ડ
-ઙ્ઢ
-ઙ્ણ
-ઙ્ત
-ઙ્થ
-ઙ્દ
-ઙ્ધ
-ઙ્ન
-ઙ્પ
-ઙ્ફ
-ઙ્બ
-ઙ્ભ
-ઙ્મ
-ઙ્ય
-ઙ્ર
-ઙ્લ
-ઙ્ળ
-ઙ્વ
-ઙ્શ
-ઙ્ષ
-ઙ્સ
-ઙ્હ
-ચ્ક
-ચ્ખ
-ચ્ગ
-ચ્ઘ
-ચ્ઙ
-ચ્ચ
-ચ્છ
-ચ્જ
-ચ્ઝ
-ચ્ઞ
-ચ્ટ
-ચ્ઠ
-ચ્ડ
-ચ્ઢ
-ચ્ણ
-ચ્ત
-ચ્થ
-ચ્દ
-ચ્ધ
-ચ્ન
-ચ્પ
-ચ્ફ
-ચ્બ
-ચ્ભ
-ચ્મ
-ચ્ય
-ચ્ર
-ચ્લ
-ચ્ળ
-ચ્વ
-ચ્શ
-ચ્ષ
-ચ્સ
-ચ્હ
-છ્ક
-છ્ખ
-છ્ગ
-છ્ઘ
-છ્ઙ
-છ્ચ
-છ્છ
-છ્જ
-છ્ઝ
-છ્ઞ
-છ્ટ
-છ્ઠ
-છ્ડ
-છ્ઢ
-છ્ણ
-છ્ત
-છ્થ
-છ્દ
-છ્ધ
-છ્ન
-છ્પ
-છ્ફ
-છ્બ
-છ્ભ
-છ્મ
-છ્ય
-છ્ર
-છ્લ
-છ્ળ
-છ્વ
-છ્શ
-છ્ષ
-છ્સ
-છ્હ
-જ્ક
-જ્ખ
-જ્ગ
-જ્ઘ
-જ્ઙ
-જ્ચ
-જ્છ
-જ્જ
-જ્ઝ
-જ્ઞ
-જ્ટ
-જ્ઠ
-જ્ડ
-જ્ઢ
-જ્ણ
-જ્ત
-જ્થ
-જ્દ
-જ્ધ
-જ્ન
-જ્પ
-જ્ફ
-જ્બ
-જ્ભ
-જ્મ
-જ્ય
-જ્ર
-જ્લ
-જ્ળ
-જ્વ
-જ્શ
-જ્ષ
-જ્સ
-જ્હ
-ઝ્ક
-ઝ્ખ
-ઝ્ગ
-ઝ્ઘ
-ઝ્ઙ
-ઝ્ચ
-ઝ્છ
-ઝ્જ
-ઝ્ઝ
-ઝ્ઞ
-ઝ્ટ
-ઝ્ઠ
-ઝ્ડ
-ઝ્ઢ
-ઝ્ણ
-ઝ્ત
-ઝ્થ
-ઝ્દ
-ઝ્ધ
-ઝ્ન
-ઝ્પ
-ઝ્ફ
-ઝ્બ
-ઝ્ભ
-ઝ્મ
-ઝ્ય
-ઝ્ર
-ઝ્લ
-ઝ્ળ
-ઝ્વ
-ઝ્શ
-ઝ્ષ
-ઝ્સ
-ઝ્હ
-ઞ્ક
-ઞ્ખ
-ઞ્ગ
-ઞ્ઘ
-ઞ્ઙ
-ઞ્ચ
-ઞ્છ
-ઞ્જ
-ઞ્ઝ
-ઞ્ઞ
-ઞ્ટ
-ઞ્ઠ
-ઞ્ડ
-ઞ્ઢ
-ઞ્ણ
-ઞ્ત
-ઞ્થ
-ઞ્દ
-ઞ્ધ
-ઞ્ન
-ઞ્પ
-ઞ્ફ
-ઞ્બ
-ઞ્ભ
-ઞ્મ
-ઞ્ય
-ઞ્ર
-ઞ્લ
-ઞ્ળ
-ઞ્વ
-ઞ્શ
-ઞ્ષ
-ઞ્સ
-ઞ્હ
-ટ્ક
-ટ્ખ
-ટ્ગ
-ટ્ઘ
-ટ્ઙ
-ટ્ચ
-ટ્છ
-ટ્જ
-ટ્ઝ
-ટ્ઞ
-ટ્ટ
-ટ્ઠ
-ટ્ડ
-ટ્ઢ
-ટ્ણ
-ટ્ત
-ટ્થ
-ટ્દ
-ટ્ધ
-ટ્ન
-ટ્પ
-ટ્ફ
-ટ્બ
-ટ્ભ
-ટ્મ
-ટ્ય
-ટ્ર
-ટ્લ
-ટ્ળ
-ટ્વ
-ટ્શ
-ટ્ષ
-ટ્સ
-ટ્હ
-ઠ્ક
-ઠ્ખ
-ઠ્ગ
-ઠ્ઘ
-ઠ્ઙ
-ઠ્ચ
-ઠ્છ
-ઠ્જ
-ઠ્ઝ
-ઠ્ઞ
-ઠ્ટ
-ઠ્ઠ
-ઠ્ડ
-ઠ્ઢ
-ઠ્ણ
-ઠ્ત
-ઠ્થ
-ઠ્દ
-ઠ્ધ
-ઠ્ન
-ઠ્પ
-ઠ્ફ
-ઠ્બ
-ઠ્ભ
-ઠ્મ
-ઠ્ય
-ઠ્ર
-ઠ્લ
-ઠ્ળ
-ઠ્વ
-ઠ્શ
-ઠ્ષ
-ઠ્સ
-ઠ્હ
-ડ્ક
-ડ્ખ
-ડ્ગ
-ડ્ઘ
-ડ્ઙ
-ડ્ચ
-ડ્છ
-ડ્જ
-ડ્ઝ
-ડ્ઞ
-ડ્ટ
-ડ્ઠ
-ડ્ડ
-ડ્ઢ
-ડ્ણ
-ડ્ત
-ડ્થ
-ડ્દ
-ડ્ધ
-ડ્ન
-ડ્પ
-ડ્ફ
-ડ્બ
-ડ્ભ
-ડ્મ
-ડ્ય
-ડ્ર
-ડ્લ
-ડ્ળ
-ડ્વ
-ડ્શ
-ડ્ષ
-ડ્સ
-ડ્હ
-ઢ્ક
-ઢ્ખ
-ઢ્ગ
-ઢ્ઘ
-ઢ્ઙ
-ઢ્ચ
-ઢ્છ
-ઢ્જ
-ઢ્ઝ
-ઢ્ઞ
-ઢ્ટ
-ઢ્ઠ
-ઢ્ડ
-ઢ્ઢ
-ઢ્ણ
-ઢ્ત
-ઢ્થ
-ઢ્દ
-ઢ્ધ
-ઢ્ન
-ઢ્પ
-ઢ્ફ
-ઢ્બ
-ઢ્ભ
-ઢ્મ
-ઢ્ય
-ઢ્ર
-ઢ્લ
-ઢ્ળ
-ઢ્વ
-ઢ્શ
-ઢ્ષ
-ઢ્સ
-ઢ્હ
-ણ્ક
-ણ્ખ
-ણ્ગ
-ણ્ઘ
-ણ્ઙ
-ણ્ચ
-ણ્છ
-ણ્જ
-ણ્ઝ
-ણ્ઞ
-ણ્ટ
-ણ્ઠ
-ણ્ડ
-ણ્ઢ
-ણ્ણ
-ણ્ત
-ણ્થ
-ણ્દ
-ણ્ધ
-ણ્ન
-ણ્પ
-ણ્ફ
-ણ્બ
-ણ્ભ
-ણ્મ
-ણ્ય
-ણ્ર
-ણ્લ
-ણ્ળ
-ણ્વ
-ણ્શ
-ણ્ષ
-ણ્સ
-ણ્હ
-ત્ક
-ત્ખ
-ત્ગ
-ત્ઘ
-ત્ઙ
-ત્ચ
-ત્છ
-ત્જ
-ત્ઝ
-ત્ઞ
-ત્ટ
-ત્ઠ
-ત્ડ
-ત્ઢ
-ત્ણ
-ત્ત
-ત્થ
-ત્દ
-ત્ધ
-ત્ન
-ત્પ
-ત્ફ
-ત્બ
-ત્ભ
-ત્મ
-ત્ય
-ત્ર
-ત્લ
-ત્ળ
-ત્વ
-ત્શ
-ત્ષ
-ત્સ
-ત્હ
-થ્ક
-થ્ખ
-થ્ગ
-થ્ઘ
-થ્ઙ
-થ્ચ
-થ્છ
-થ્જ
-થ્ઝ
-થ્ઞ
-થ્ટ
-થ્ઠ
-થ્ડ
-થ્ઢ
-થ્ણ
-થ્ત
-થ્થ
-થ્દ
-થ્ધ
-થ્ન
-થ્પ
-થ્ફ
-થ્બ
-થ્ભ
-થ્મ
-થ્ય
-થ્ર
-થ્લ
-થ્ળ
-થ્વ
-થ્શ
-થ્ષ
-થ્સ
-થ્હ
-દ્ક
-દ્ખ
-દ્ગ
-દ્ઘ
-દ્ઙ
-દ્ચ
-દ્છ
-દ્જ
-દ્ઝ
-દ્ઞ
-દ્ટ
-દ્ઠ
-દ્ડ
-દ્ઢ
-દ્ણ
-દ્ત
-દ્થ
-દ્દ
-દ્ધ
-દ્ન
-દ્પ
-દ્ફ
-દ્બ
-દ્ભ
-દ્મ
-દ્ય
-દ્ર
-દ્લ
-દ્ળ
-દ્વ
-દ્શ
-દ્ષ
-દ્સ
-દ્હ
-ધ્ક
-ધ્ખ
-ધ્ગ
-ધ્ઘ
-ધ્ઙ
-ધ્ચ
-ધ્છ
-ધ્જ
-ધ્ઝ
-ધ્ઞ
-ધ્ટ
-ધ્ઠ
-ધ્ડ
-ધ્ઢ
-ધ્ણ
-ધ્ત
-ધ્થ
-ધ્દ
-ધ્ધ
-ધ્ન
-ધ્પ
-ધ્ફ
-ધ્બ
-ધ્ભ
-ધ્મ
-ધ્ય
-ધ્ર
-ધ્લ
-ધ્ળ
-ધ્વ
-ધ્શ
-ધ્ષ
-ધ્સ
-ધ્હ
-ન્ક
-ન્ખ
-ન્ગ
-ન્ઘ
-ન્ઙ
-ન્ચ
-ન્છ
-ન્જ
-ન્ઝ
-ન્ઞ
-ન્ટ
-ન્ઠ
-ન્ડ
-ન્ઢ
-ન્ણ
-ન્ત
-ન્થ
-ન્દ
-ન્ધ
-ન્ન
-ન્પ
-ન્ફ
-ન્બ
-ન્ભ
-ન્મ
-ન્ય
-ન્ર
-ન્લ
-ન્ળ
-ન્વ
-ન્શ
-ન્ષ
-ન્સ
-ન્હ
-પ્ક
-પ્ખ
-પ્ગ
-પ્ઘ
-પ્ઙ
-પ્ચ
-પ્છ
-પ્જ
-પ્ઝ
-પ્ઞ
-પ્ટ
-પ્ઠ
-પ્ડ
-પ્ઢ
-પ્ણ
-પ્ત
-પ્થ
-પ્દ
-પ્ધ
-પ્ન
-પ્પ
-પ્ફ
-પ્બ
-પ્ભ
-પ્મ
-પ્ય
-પ્ર
-પ્લ
-પ્ળ
-પ્વ
-પ્શ
-પ્ષ
-પ્સ
-પ્હ
-ફ્ક
-ફ્ખ
-ફ્ગ
-ફ્ઘ
-ફ્ઙ
-ફ્ચ
-ફ્છ
-ફ્જ
-ફ્ઝ
-ફ્ઞ
-ફ્ટ
-ફ્ઠ
-ફ્ડ
-ફ્ઢ
-ફ્ણ
-ફ્ત
-ફ્થ
-ફ્દ
-ફ્ધ
-ફ્ન
-ફ્પ
-ફ્ફ
-ફ્બ
-ફ્ભ
-ફ્મ
-ફ્ય
-ફ્ર
-ફ્લ
-ફ્ળ
-ફ્વ
-ફ્શ
-ફ્ષ
-ફ્સ
-ફ્હ
-બ્ક
-બ્ખ
-બ્ગ
-બ્ઘ
-બ્ઙ
-બ્ચ
-બ્છ
-બ્જ
-બ્ઝ
-બ્ઞ
-બ્ટ
-બ્ઠ
-બ્ડ
-બ્ઢ
-બ્ણ
-બ્ત
-બ્થ
-બ્દ
-બ્ધ
-બ્ન
-બ્પ
-બ્ફ
-બ્બ
-બ્ભ
-બ્મ
-બ્ય
-બ્ર
-બ્લ
-બ્ળ
-બ્વ
-બ્શ
-બ્ષ
-બ્સ
-બ્હ
-ભ્ક
-ભ્ખ
-ભ્ગ
-ભ્ઘ
-ભ્ઙ
-ભ્ચ
-ભ્છ
-ભ્જ
-ભ્ઝ
-ભ્ઞ
-ભ્ટ
-ભ્ઠ
-ભ્ડ
-ભ્ઢ
-ભ્ણ
-ભ્ત
-ભ્થ
-ભ્દ
-ભ્ધ
-ભ્ન
-ભ્પ
-ભ્ફ
-ભ્બ
-ભ્ભ
-ભ્મ
-ભ્ય
-ભ્ર
-ભ્લ
-ભ્ળ
-ભ્વ
-ભ્શ
-ભ્ષ
-ભ્સ
-ભ્હ
-મ્ક
-મ્ખ
-મ્ગ
-મ્ઘ
-મ્ઙ
-મ્ચ
-મ્છ
-મ્જ
-મ્ઝ
-મ્ઞ
-મ્ટ
-મ્ઠ
-મ્ડ
-મ્ઢ
-મ્ણ
-મ્ત
-મ્થ
-મ્દ
-મ્ધ
-મ્ન
-મ્પ
-મ્ફ
-મ્બ
-મ્ભ
-મ્મ
-મ્ય
-મ્ર
-મ્લ
-મ્ળ
-મ્વ
-મ્શ
-મ્ષ
-મ્સ
-મ્હ
-ય્ક
-ય્ખ
-ય્ગ
-ય્ઘ
-ય્ઙ
-ય્ચ
-ય્છ
-ય્જ
-ય્ઝ
-ય્ઞ
-ય્ટ
-ય્ઠ
-ય્ડ
-ય્ઢ
-ય્ણ
-ય્ત
-ય્થ
-ય્દ
-ય્ધ
-ય્ન
-ય્પ
-ય્ફ
-ય્બ
-ય્ભ
-ય્મ
-ય્ય
-ય્ર
-ય્લ
-ય્ળ
-ય્વ
-ય્શ
-ય્ષ
-ય્સ
-ય્હ
-ર્ક
-ર્ખ
-ર્ગ
-ર્ઘ
-ર્ઙ
-ર્ચ
-ર્છ
-ર્જ
-ર્ઝ
-ર્ઞ
-ર્ટ
-ર્ઠ
-ર્ડ
-ર્ઢ
-ર્ણ
-ર્ત
-ર્થ
-ર્દ
-ર્ધ
-ર્ન
-ર્પ
-ર્ફ
-ર્બ
-ર્ભ
-ર્મ
-ર્ય
-ર્ર
-ર્લ
-ર્ળ
-ર્વ
-ર્શ
-ર્ષ
-ર્સ
-ર્હ
-લ્ક
-લ્ખ
-લ્ગ
-લ્ઘ
-લ્ઙ
-લ્ચ
-લ્છ
-લ્જ
-લ્ઝ
-લ્ઞ
-લ્ટ
-લ્ઠ
-લ્ડ
-લ્ઢ
-લ્ણ
-લ્ત
-લ્થ
-લ્દ
-લ્ધ
-લ્ન
-લ્પ
-લ્ફ
-લ્બ
-લ્ભ
-લ્મ
-લ્ય
-લ્ર
-લ્લ
-લ્ળ
-લ્વ
-લ્શ
-લ્ષ
-લ્સ
-લ્હ
-ળ્ક
-ળ્ખ
-ળ્ગ
-ળ્ઘ
-ળ્ઙ
-ળ્ચ
-ળ્છ
-ળ્જ
-ળ્ઝ
-ળ્ઞ
-ળ્ટ
-ળ્ઠ
-ળ્ડ
-ળ્ઢ
-ળ્ણ
-ળ્ત
-ળ્થ
-ળ્દ
-ળ્ધ
-ળ્ન
-ળ્પ
-ળ્ફ
-ળ્બ
-ળ્ભ
-ળ્મ
-ળ્ય
-ળ્ર
-ળ્લ
-ળ્ળ
-ળ્વ
-ળ્શ
-ળ્ષ
-ળ્સ
-ળ્હ
-વ્ક
-વ્ખ
-વ્ગ
-વ્ઘ
-વ્ઙ
-વ્ચ
-વ્છ
-વ્જ
-વ્ઝ
-વ્ઞ
-વ્ટ
-વ્ઠ
-વ્ડ
-વ્ઢ
-વ્ણ
-વ્ત
-વ્થ
-વ્દ
-વ્ધ
-વ્ન
-વ્પ
-વ્ફ
-વ્બ
-વ્ભ
-વ્મ
-વ્ય
-વ્ર
-વ્લ
-વ્ળ
-વ્વ
-વ્શ
-વ્ષ
-વ્સ
-વ્હ
-શ્ક
-શ્ખ
-શ્ગ
-શ્ઘ
-શ્ઙ
-શ્ચ
-શ્છ
-શ્જ
-શ્ઝ
-શ્ઞ
-શ્ટ
-શ્ઠ
-શ્ડ
-શ્ઢ
-શ્ણ
-શ્ત
-શ્થ
-શ્દ
-શ્ધ
-શ્ન
-શ્પ
-શ્ફ
-શ્બ
-શ્ભ
-શ્મ
-શ્ય
-શ્ર
-શ્લ
-શ્ળ
-શ્વ
-શ્શ
-શ્ષ
-શ્સ
-શ્હ
-ષ્ક
-ષ્ખ
-ષ્ગ
-ષ્ઘ
-ષ્ઙ
-ષ્ચ
-ષ્છ
-ષ્જ
-ષ્ઝ
-ષ્ઞ
-ષ્ટ
-ષ્ઠ
-ષ્ડ
-ષ્ઢ
-ષ્ણ
-ષ્ત
-ષ્થ
-ષ્દ
-ષ્ધ
-ષ્ન
-ષ્પ
-ષ્ફ
-ષ્બ
-ષ્ભ
-ષ્મ
-ષ્ય
-ષ્ર
-ષ્લ
-ષ્ળ
-ષ્વ
-ષ્શ
-ષ્ષ
-ષ્સ
-ષ્હ
-સ્ક
-સ્ખ
-સ્ગ
-સ્ઘ
-સ્ઙ
-સ્ચ
-સ્છ
-સ્જ
-સ્ઝ
-સ્ઞ
-સ્ટ
-સ્ઠ
-સ્ડ
-સ્ઢ
-સ્ણ
-સ્ત
-સ્થ
-સ્દ
-સ્ધ
-સ્ન
-સ્પ
-સ્ફ
-સ્બ
-સ્ભ
-સ્મ
-સ્ય
-સ્ર
-સ્લ
-સ્ળ
-સ્વ
-સ્શ
-સ્ષ
-સ્સ
-સ્હ
-હ્ક
-હ્ખ
-હ્ગ
-હ્ઘ
-હ્ઙ
-હ્ચ
-હ્છ
-હ્જ
-હ્ઝ
-હ્ઞ
-હ્ટ
-હ્ઠ
-હ્ડ
-હ્ઢ
-હ્ણ
-હ્ત
-હ્થ
-હ્દ
-હ્ધ
-હ્ન
-હ્પ
-હ્ફ
-હ્બ
-હ્ભ
-હ્મ
-હ્ય
-હ્ર
-હ્લ
-હ્ળ
-હ્વ
-હ્શ
-હ્ષ
-હ્સ
-હ્હ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
deleted file mode 100644
index b2adaabd2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-ਆ ਅਾ
-ਇ ੲਿ
-ਈ ੲੀ
-ਉ ੳੁ
-ਊ ੳੂ
-ਏ ੲੇ
-ਐ ਅੈ
-ਓ ੳੋ
-ਔ ਅੌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
deleted file mode 100644
index 27a39f65c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ਕ੍ਹ
-ਤ੍ਯੋ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index ee8b3be7a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-ਕ
-ਖ
-ਗ
-ਘ
-ਙ
-ਚ
-ਛ
-ਜ
-ਝ
-ਞ
-ਟ
-ਠ
-ਡ
-ਢ
-ਣ
-ਤ
-ਥ
-ਦ
-ਧ
-ਨ
-ਪ
-ਫ
-ਬ
-ਭ
-ਮ
-ਯ
-ਰ
-ਲ
-ਲ਼
-ਵ
-ਸ਼
-ਸ
-ਹ
-ਖ਼
-ਗ਼
-ਜ਼
-ੜ
-ਫ਼
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index a934caaa4..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-ਾ
-ਿ
-ੀ
-ੁ
-ੂ
-ੇ
-ੈ
-ੋ
-ੌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index d08b7a860..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-੦
-੧
-੨
-੩
-੪
-੫
-੬
-੭
-੮
-੯
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
deleted file mode 100644
index 8565c887a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-ੰ
-ੱ
-ੲ
-ੳ
-ੴ
-ੵ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 05827ca9d..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-ਅ
-ਆ
-ਇ
-ਈ
-ਉ
-ਊ
-ਏ
-ਐ
-ਓ
-ਔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index adb725e15..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-ਁ
-ਂ
-ਃ
-਼
-੍
-ੑ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 7fdf6e45c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-ਉਂ
-ਊਂ
-ਏਂ
-ਐਂ
-ਓਂ
-ਔਂ
-ਠਂ
-ਠੇ
-ਠੈ
-ਠੋ
-ਠੌ
-ਠੰ
-ਨਂ
-ਨੇ
-ਨੈ
-ਨੋ
-ਨੌ
-ਨੰ
-ਠੱ
-ਨੱ
-ਲੱ
-ਲ਼ੱ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index 63d54a50a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ੳ
-ੲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index eb2e8eefd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,152 +0,0 @@
-ਕ੍ਯ
-ਖ੍ਯ
-ਗ੍ਯ
-ਘ੍ਯ
-ਙ੍ਯ
-ਚ੍ਯ
-ਛ੍ਯ
-ਜ੍ਯ
-ਝ੍ਯ
-ਞ੍ਯ
-ਟ੍ਯ
-ਠ੍ਯ
-ਡ੍ਯ
-ਢ੍ਯ
-ਣ੍ਯ
-ਤ੍ਯ
-ਥ੍ਯ
-ਦ੍ਯ
-ਧ੍ਯ
-ਨ੍ਯ
-ਪ੍ਯ
-ਫ੍ਯ
-ਬ੍ਯ
-ਭ੍ਯ
-ਮ੍ਯ
-ਯ੍ਯ
-ਰ੍ਯ
-ਲ੍ਯ
-ਲ਼੍ਯ
-ਵ੍ਯ
-ਸ਼੍ਯ
-ਸ੍ਯ
-ਹ੍ਯ
-ਖ਼੍ਯ
-ਗ਼੍ਯ
-ਜ਼੍ਯ
-ੜ੍ਯ
-ਫ਼੍ਯ
-ਕ੍ਰ
-ਖ੍ਰ
-ਗ੍ਰ
-ਘ੍ਰ
-ਙ੍ਰ
-ਚ੍ਰ
-ਛ੍ਰ
-ਜ੍ਰ
-ਝ੍ਰ
-ਞ੍ਰ
-ਟ੍ਰ
-ਠ੍ਰ
-ਡ੍ਰ
-ਢ੍ਰ
-ਣ੍ਰ
-ਤ੍ਰ
-ਥ੍ਰ
-ਦ੍ਰ
-ਧ੍ਰ
-ਨ੍ਰ
-ਪ੍ਰ
-ਫ੍ਰ
-ਬ੍ਰ
-ਭ੍ਰ
-ਮ੍ਰ
-ਯ੍ਰ
-ਰ੍ਰ
-ਲ੍ਰ
-ਲ਼੍ਰ
-ਵ੍ਰ
-ਸ਼੍ਰ
-ਸ੍ਰ
-ਹ੍ਰ
-ਖ਼੍ਰ
-ਗ਼੍ਰ
-ਜ਼੍ਰ
-ੜ੍ਰ
-ਫ਼੍ਰ
-ਕ੍ਵ
-ਖ੍ਵ
-ਗ੍ਵ
-ਘ੍ਵ
-ਙ੍ਵ
-ਚ੍ਵ
-ਛ੍ਵ
-ਜ੍ਵ
-ਝ੍ਵ
-ਞ੍ਵ
-ਟ੍ਵ
-ਠ੍ਵ
-ਡ੍ਵ
-ਢ੍ਵ
-ਣ੍ਵ
-ਤ੍ਵ
-ਥ੍ਵ
-ਦ੍ਵ
-ਧ੍ਵ
-ਨ੍ਵ
-ਪ੍ਵ
-ਫ੍ਵ
-ਬ੍ਵ
-ਭ੍ਵ
-ਮ੍ਵ
-ਯ੍ਵ
-ਰ੍ਵ
-ਲ੍ਵ
-ਲ਼੍ਵ
-ਵ੍ਵ
-ਸ਼੍ਵ
-ਸ੍ਵ
-ਹ੍ਵ
-ਖ਼੍ਵ
-ਗ਼੍ਵ
-ਜ਼੍ਵ
-ੜ੍ਵ
-ਫ਼੍ਵ
-ਕ੍ਹ
-ਖ੍ਹ
-ਗ੍ਹ
-ਘ੍ਹ
-ਙ੍ਹ
-ਚ੍ਹ
-ਛ੍ਹ
-ਜ੍ਹ
-ਝ੍ਹ
-ਞ੍ਹ
-ਟ੍ਹ
-ਠ੍ਹ
-ਡ੍ਹ
-ਢ੍ਹ
-ਣ੍ਹ
-ਤ੍ਹ
-ਥ੍ਹ
-ਦ੍ਹ
-ਧ੍ਹ
-ਨ੍ਹ
-ਪ੍ਹ
-ਫ੍ਹ
-ਬ੍ਹ
-ਭ੍ਹ
-ਮ੍ਹ
-ਯ੍ਹ
-ਰ੍ਹ
-ਲ੍ਹ
-ਲ਼੍ਹ
-ਵ੍ਹ
-ਸ਼੍ਹ
-ਸ੍ਹ
-ਹ੍ਹ
-ਖ਼੍ਹ
-ਗ਼੍ਹ
-ਜ਼੍ਹ
-ੜ੍ਹ
-ਫ਼੍ਹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
deleted file mode 100644
index cc05db93f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ಊ ಉಾ
-ಔ ಒೌ
-ೠ ಋಾ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
deleted file mode 100644
index a8a632505..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-ಕ್ರ
-ನ್ಡ
-ನ್ನ
-ಯೂ
-ರ್ಕ
-ರ್ಮ
-ರ್‍ಕ
-ವೋ
-ಷೆ
-ಷ್
-ೠ
-೦೧೨
-ಕೀ
-ಕೊ
-ಕೇ
-ಕೈ
-ಕೋ
-ಕ್ಷ
-ಕ್ಷಿ
-ಚ್ಚ್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt
deleted file mode 100644
index 3130f3545..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-ಸ್ಕು
-ಸ್ಕೂ
-ಸ್ಕೃ
-ಸ್ಕೄ
-ಸ್ಕಾ
-ಸ್ಕೕ
-ಸ್ಕೕ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644
index fff748acf..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
+++ /dev/null
@@ -1 +0,0 @@
-ೞ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index f641547b2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ೠ
-ೡ
-ೢ
-ೣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 650cbf757..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-ಕ
-ಖ
-ಗ
-ಘ
-ಙ
-ಚ
-ಛ
-ಜ
-ಝ
-ಞ
-ಟ
-ಠ
-ಡ
-ಢ
-ಣ
-ತ
-ಥ
-ದ
-ಧ
-ನ
-ಪ
-ಫ
-ಬ
-ಭ
-ಮ
-ಯ
-ರ
-ಱ
-ಲ
-ಳ
-ವ
-ಶ
-ಷ
-ಸ
-ಹ
-ಂ
-ಃ
-಼
-ಽ
-್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index 476f39fc1..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-ಾ
-ಿ
-ೀ
-ು
-ೂ
-ೃ
-ೄ
-ೆ
-ೇ
-ೈ
-ೊ
-ೋ
-ೌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 57ac088f9..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-೦
-೧
-೨
-೩
-೪
-೫
-೬
-೭
-೮
-೯
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 38f171926..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-ಅ
-ಆ
-ಇ
-ಈ
-ಉ
-ಊ
-ಋ
-ಌ
-ಎ
-ಏ
-ಐ
-ಒ
-ಓ
-ಔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 6bbf23e25..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-ಂ
-ಃ
-಼
-ಽ
-್
-ೕ
-ೖ
-ೱ
-ೲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 4cc0f5697..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,188 +0,0 @@
-ಕಾ
-ಖಾ
-ಗಾ
-ಠಾ
-ಡಾ
-ಛಾ
-ಕಿ
-ಖಿ
-ಗಿ
-ಘಿ
-ಙಿ
-ಚಿ
-ಛಿ
-ಜಿ
-ಝಿ
-ಞಿ
-ಟಿ
-ಠಿ
-ಡಿ
-ಢಿ
-ಣಿ
-ತಿ
-ಥಿ
-ದಿ
-ಧಿ
-ನಿ
-ಪಿ
-ಫಿ
-ಬಿ
-ಭಿ
-ಮಿ
-ಯಿ
-ರಿ
-ಱಿ
-ಲಿ
-ಳಿ
-ವಿ
-ಶಿ
-ಷಿ
-ಸಿ
-ಹಿ
-ಕು
-ಗು
-ಜು
-ಟು
-ತು
-ಖು
-ಕೂ
-ಖೂ
-ಗೂ
-ಟೂ
-ಚೂ
-ಛೂ
-ಕೄ
-ಗೄ
-ಜೄ
-ಟೄ
-ತೄ
-ಖೄ
-ಕೇ
-ಗೇ
-ಜೇ
-ಟೇ
-ತೇ
-ಖೇ
-ಕೈ
-ಗೈ
-ಜೈ
-ಟೈ
-ತೈ
-ಖೈ
-ಕೊ
-ಗೊ
-ಜೊ
-ಟೊ
-ತೊ
-ಖೊ
-ಕೋ
-ಗೋ
-ಜೋ
-ಟೋ
-ತೋ
-ಖೋ
-ಕೆ
-ಖೆ
-ಗೆ
-ಘೆ
-ಙೆ
-ಚೆ
-ಛೆ
-ಜೆ
-ಝೆ
-ಞೆ
-ಟೆ
-ಠೆ
-ಡೆ
-ಢೆ
-ಣೆ
-ತೆ
-ಥೆ
-ದೆ
-ಧೆ
-ನೆ
-ಪೆ
-ಫೆ
-ಬೆ
-ಭೆ
-ಮೆ
-ಯೆ
-ರೆ
-ಱೆ
-ಲೆ
-ಳೆ
-ವೆ
-ಶೆ
-ಷೆ
-ಸೆ
-ಹೆ
-ಕೌ
-ಖೌ
-ಗೌ
-ಘೌ
-ಙೌ
-ಚೌ
-ಛೌ
-ಜೌ
-ಝೌ
-ಞೌ
-ಟೌ
-ಠೌ
-ಡೌ
-ಢೌ
-ಣೌ
-ತೌ
-ಥೌ
-ದೌ
-ಧೌ
-ನೌ
-ಪೌ
-ಫೌ
-ಬೌ
-ಭೌ
-ಮೌ
-ಯೌ
-ರೌ
-ಱೌ
-ಲೌ
-ಳೌ
-ವೌ
-ಶೌ
-ಷೌ
-ಸೌ
-ಹೌ
-ಕ್
-ಖ್
-ಗ್
-ಘ್
-ಙ್
-ಚ್
-ಛ್
-ಜ್
-ಝ್
-ಞ್
-ಟ್
-ಠ್
-ಡ್
-ಢ್
-ಣ್
-ತ್
-ಥ್
-ದ್
-ಧ್
-ನ್
-ಪ್
-ಫ್
-ಬ್
-ಭ್
-ಮ್
-ಯ್
-ರ್
-ಱ್
-ಲ್
-ಳ್
-ವ್
-ಶ್
-ಷ್
-ಸ್
-ಹ್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 583072df8..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,306 +0,0 @@
-ಕ್ಕ
-ಕ್ಖ
-ಕ್ಗ
-ಕ್ಘ
-ಕ್ಙ
-ಕ್ಚ
-ಕ್ಛ
-ಕ್ಜ
-ಕ್ಝ
-ಕ್ಞ
-ಕ್ಟ
-ಕ್ಠ
-ಕ್ಡ
-ಕ್ಢ
-ಕ್ಣ
-ಕ್ತ
-ಕ್ಥ
-ಕ್ದ
-ಕ್ಧ
-ಕ್ನ
-ಕ್ಪ
-ಕ್ಫ
-ಕ್ಬ
-ಕ್ಭ
-ಕ್ಮ
-ಕ್ಯ
-ಕ್ರ
-ಕ್ಲ
-ಕ್ಳ
-ಕ್ವ
-ಕ್ಶ
-ಕ್ಷ
-ಕ್ಸ
-ಕ್ಹ
-ತ್ಕ
-ತ್ಖ
-ತ್ಗ
-ತ್ಘ
-ತ್ಙ
-ತ್ಚ
-ತ್ಛ
-ತ್ಜ
-ತ್ಝ
-ತ್ಞ
-ತ್ಟ
-ತ್ಠ
-ತ್ಡ
-ತ್ಢ
-ತ್ಣ
-ತ್ತ
-ತ್ಥ
-ತ್ದ
-ತ್ಧ
-ತ್ನ
-ತ್ಪ
-ತ್ಫ
-ತ್ಬ
-ತ್ಭ
-ತ್ಮ
-ತ್ಯ
-ತ್ರ
-ತ್ಲ
-ತ್ಳ
-ತ್ವ
-ತ್ಶ
-ತ್ಷ
-ತ್ಸ
-ತ್ಹ
-ನ್ಕ
-ನ್ಖ
-ನ್ಗ
-ನ್ಘ
-ನ್ಙ
-ನ್ಚ
-ನ್ಛ
-ನ್ಜ
-ನ್ಝ
-ನ್ಞ
-ನ್ಟ
-ನ್ಠ
-ನ್ಡ
-ನ್ಢ
-ನ್ಣ
-ನ್ತ
-ನ್ಥ
-ನ್ದ
-ನ್ಧ
-ನ್ನ
-ನ್ಪ
-ನ್ಫ
-ನ್ಬ
-ನ್ಭ
-ನ್ಮ
-ನ್ಯ
-ನ್ರ
-ನ್ಲ
-ನ್ಳ
-ನ್ವ
-ನ್ಶ
-ನ್ಷ
-ನ್ಸ
-ನ್ಹ
-ಮ್ಕ
-ಮ್ಖ
-ಮ್ಗ
-ಮ್ಘ
-ಮ್ಙ
-ಮ್ಚ
-ಮ್ಛ
-ಮ್ಜ
-ಮ್ಝ
-ಮ್ಞ
-ಮ್ಟ
-ಮ್ಠ
-ಮ್ಡ
-ಮ್ಢ
-ಮ್ಣ
-ಮ್ತ
-ಮ್ಥ
-ಮ್ದ
-ಮ್ಧ
-ಮ್ನ
-ಮ್ಪ
-ಮ್ಫ
-ಮ್ಬ
-ಮ್ಭ
-ಮ್ಮ
-ಮ್ಯ
-ಮ್ರ
-ಮ್ಲ
-ಮ್ಳ
-ಮ್ವ
-ಮ್ಶ
-ಮ್ಷ
-ಮ್ಸ
-ಮ್ಹ
-ಯ್ಕ
-ಯ್ಖ
-ಯ್ಗ
-ಯ್ಘ
-ಯ್ಙ
-ಯ್ಚ
-ಯ್ಛ
-ಯ್ಜ
-ಯ್ಝ
-ಯ್ಞ
-ಯ್ಟ
-ಯ್ಠ
-ಯ್ಡ
-ಯ್ಢ
-ಯ್ಣ
-ಯ್ತ
-ಯ್ಥ
-ಯ್ದ
-ಯ್ಧ
-ಯ್ನ
-ಯ್ಪ
-ಯ್ಫ
-ಯ್ಬ
-ಯ್ಭ
-ಯ್ಮ
-ಯ್ಯ
-ಯ್ರ
-ಯ್ಲ
-ಯ್ಳ
-ಯ್ವ
-ಯ್ಶ
-ಯ್ಷ
-ಯ್ಸ
-ಯ್ಹ
-ರ್ಕ
-ರ್ಖ
-ರ್ಗ
-ರ್ಘ
-ರ್ಙ
-ರ್ಚ
-ರ್ಛ
-ರ್ಜ
-ರ್ಝ
-ರ್ಞ
-ರ್ಟ
-ರ್ಠ
-ರ್ಡ
-ರ್ಢ
-ರ್ಣ
-ರ್ತ
-ರ್ಥ
-ರ್ದ
-ರ್ಧ
-ರ್ನ
-ರ್ಪ
-ರ್ಫ
-ರ್ಬ
-ರ್ಭ
-ರ್ಮ
-ರ್ಯ
-ರ್ರ
-ರ್ಲ
-ರ್ಳ
-ರ್ವ
-ರ್ಶ
-ರ್ಷ
-ರ್ಸ
-ರ್ಹ
-ರ್ಕ
-ರ್ಖ
-ರ್ಗ
-ರ್ಘ
-ರ್ಙ
-ರ್ಚ
-ರ್ಛ
-ರ್ಜ
-ರ್ಝ
-ರ್ಞ
-ರ್ಟ
-ರ್ಠ
-ರ್ಡ
-ರ್ಢ
-ರ್ಣ
-ರ್ತ
-ರ್ಥ
-ರ್ದ
-ರ್ಧ
-ರ್ನ
-ರ್ಪ
-ರ್ಫ
-ರ್ಬ
-ರ್ಭ
-ರ್ಮ
-ರ್ಯ
-ರ್ರ
-ರ್ಲ
-ರ್ಳ
-ರ್ವ
-ರ್ಶ
-ರ್ಷ
-ರ್ಸ
-ರ್ಹ
-ಲ್ಕ
-ಲ್ಖ
-ಲ್ಗ
-ಲ್ಘ
-ಲ್ಙ
-ಲ್ಚ
-ಲ್ಛ
-ಲ್ಜ
-ಲ್ಝ
-ಲ್ಞ
-ಲ್ಟ
-ಲ್ಠ
-ಲ್ಡ
-ಲ್ಢ
-ಲ್ಣ
-ಲ್ತ
-ಲ್ಥ
-ಲ್ದ
-ಲ್ಧ
-ಲ್ನ
-ಲ್ಪ
-ಲ್ಫ
-ಲ್ಬ
-ಲ್ಭ
-ಲ್ಮ
-ಲ್ಯ
-ಲ್ರ
-ಲ್ಲ
-ಲ್ಳ
-ಲ್ವ
-ಲ್ಶ
-ಲ್ಷ
-ಲ್ಸ
-ಲ್ಹ
-ವ್ಕ
-ವ್ಖ
-ವ್ಗ
-ವ್ಘ
-ವ್ಙ
-ವ್ಚ
-ವ್ಛ
-ವ್ಜ
-ವ್ಝ
-ವ್ಞ
-ವ್ಟ
-ವ್ಠ
-ವ್ಡ
-ವ್ಢ
-ವ್ಣ
-ವ್ತ
-ವ್ಥ
-ವ್ದ
-ವ್ಧ
-ವ್ನ
-ವ್ಪ
-ವ್ಫ
-ವ್ಬ
-ವ್ಭ
-ವ್ಮ
-ವ್ಯ
-ವ್ರ
-ವ್ಲ
-ವ್ಳ
-ವ್ವ
-ವ್ಶ
-ವ್ಷ
-ವ್ಸ
-ವ್ಹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
deleted file mode 100644
index 061c642f7..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-ഈ ഇൗ
-ഊ ഉൗ
-ഐ എെ
-ഓ ഒാ
-ഔ ഒൗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
deleted file mode 100644
index 3d5386770..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
+++ /dev/null
@@ -1,188 +0,0 @@
-2ാം
-2-ാം
-ല്ം
-എ്ന
-9-൹
-₹100
-൦
-൧
-൨
-൩
-൪
-൫
-൬
-൭
-൮
-൯
-൰
-൱
-൲
-൳
-൴
-൵
-അങ്ങ്
-അത്
-അർത്ഥം
-അന്ധൻ
-അന്യം
-അന്വയം
-അൽപ്പം
-അമ്മ
-അമ്ലം
-അല്പം
-അല
-അവൻ
-അവന്
-അവനു്
-അസോഽസൗ
-അഹല്യ
-അഺ്
-ആമ്പിൿ
-ആല
-ആാ
-ആാാാ
-ഇൻക
-ഇല്ല
-ഇല
-ഇള
-ഇഴ
-ഈറ
-ഈൗ
-ഉമ
-ഉള്ള
-ഊമ
-ഊൗ
-ഋതു
-ൠന്ന്
-ഌകാരം
-ൡതം
-എന്ന
-എന്റെ
-എലി
-എൻറോൾ
-ഏലം
-ഐക്യം
-ഒരു
-ഓരം
-ഓാാാ
-ഔഷധം
-ഔൗ
-കണ്ഢം
-കണ്ണ്
-കണ്വൻ
-കഥ
-കമ്പം
-കമ്രം
-കല്മഷം
-കല
-കാാ
-കീീ
-കുണ്ഠിതം
-കൂൂ
-കൄന്ന്
-കൢപ്തം
-കൣതം
-കൌതുകം
-ക്രൌഞ്ചം
-ഗങ്ഗ
-ഗരം
-ങഞ
-അച്ഛൻ
-ങ്യാവൂ
-ചരം
-ഛായ
-ജലം
-ജാള്യം
-ഝാൻസി
-ഞാൻ
-ടിപ്പു
-ഡപ്പി
-തത്ത
-തെരഞ്ഞെടുപ്പിന്‍െറ
-ദയ
-ദുഃഖം
-ദൃഢം
-ധനം
-നഖം
-നന്ദി
-നന്ന്
-നന്മ
-നാണ്യം
-തന്ത
-ന്രസ്ഥി
-പച്ച
-പട്ട
-പണ്ടു്
-പല
-പറ
-പാഠം
-പാണ്ഡു
-പാണ്ഡ്യൻ
-പാന്ഥൻ
-പാറ്റ
-പിന്നെ
-പുച്ഛം
-പുഞ്ച
-പൊൻനാണ്യം
-ഫലം
-ബലം
-ഭയം
-ഭാൎയ്യ
-ഭാര്യ
-മങ്ക
-മണം
-മണ്ട
-മ്അദനി
-മയം
-മേഘം
-മോഹന്‍ലാല്‍
-യതി
-രണ്ട്
-രമ്യം
-ലത
-അറബ്‌ബസ്സാർ
-ലോക്‌സഭ
-വഅള്
-വരം
-വാഞ്ഛ
-വില്വാദ്രി
-വെണ്മ
-ഷാരം
-ശ്രുതി
-ശരം
-ശാർങ്ഗപക്ഷി
-സമ്യക്
-സംയോഗം
-സംരംഭം
-സമ്രാട്ട്
-സസ്യം
-സാരം
-സ്രാവം
-സ്ലാവിക്
-സ്വരം
-സ്വാതന്ത്ര്യം
-സ്ട്രാപ്പ്
-സ്റ്റിംഗ്
-സ്റ്റ്രീം
-ഹാരം
-റിപ്പോര്‍ട്ട്
-  ന്‍റെ
-ന്റെ
-ൻ്റെ
-ച്ച്യൂ
-യ്ക്ക്യൂ
-ട്ട്യൂ
-യ‍്യ
-വ‍്വ
-ഹൈലൈറ്റ്സ്
- ച്ല്‍സി
-മലയാളത്തില്‍
-ഡിപ്പാർട്ട്മെന്റിന്റെ
-യ്യ്ര
- യ്യ്ര
- ്യ്ര
- ്യ്യ്ര
-വ്വ്ര
- വ്വ്ര
- ്വ്ര
- ്വ്വ്ര
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt
deleted file mode 100644
index fc74da92d..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-ൎക
-ൎക്ക്ര
-ൎന്ന
-ൎഗ്ഗ്രോ
-ൎഗ്രോ
-ൎഗോ
-ൎഗ
-ഗ്ഗ്രോ
-ഗ്ഗ്ര
-ഗ്ഗോ
-ഗ്ഗ
-ഗ്രോ
-ൎകു
-ൎക്കു
-ൎച്ച്
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
deleted file mode 100644
index 2e732ae8d..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-അൎത്ഥം
-അഥൎവ്വം
-ക്‍
-കായ്‌കറി
-കാര്‍ക്കോടകന്‍
-കുറ്റ്യാടി
-കെ
-കേ
-കൈ
-കൊ
-കോ
-കൌ
-ക്കെ
-ക്കൊ
-ക്ത്ര
-ക്യ
-ക്വ
-ഖ്യ
-ഖ്ര
-ഗ്ദ്ധ്രോ
-ട്ട
-ട്ടു്
-ണ്‍
-ണ്ട
-ത്ത
-ത്തെ
-ത്തൊ
-ദ്ദ
-ന്‍
-ന്ത
-ന്ത്യ
-ന്ത്ര്യ
-പ്ര
-പ്ലോ
-മുഖ്യമന്ത്രി
-മ്പ
-യാത്രാകൂലി
-യും
-യ്ക്കു
-യ്യ
-ര്
-ര്‍
-ര്ക
-ര്യ
-ര്‍വ്വ
-ല്‍
-ല്യ
-ല്ല
-ല്ലാം
-വ്വ
-ഷ്ട്രീ
-സോഫ്റ്റ്‌വെയര്‍
-സ്പ്രി
-സ്പ്രേ
-സ്പ്ലേ
-സ്വാതന്ത്ര്യം
-ഹാര്‍ഡ്‌വെയര്‍
-ള്‍
-ള്യം
-ള്ള
-ല്‍പ്പേ
-ശിം‌
-കോം‌
-യ‍്യ
-സ്റ്റ്
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index 0d1a19bd2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ൠ
-ൡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 4924e56ea..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-ക
-ഖ
-ഗ
-ഘ
-ങ
-ച
-ഛ
-ജ
-ഝ
-ഞ
-ട
-ഠ
-ഡ
-ഢ
-ണ
-ത
-ഥ
-ദ
-ധ
-ന
-പ
-ഫ
-ബ
-ഭ
-മ
-യ
-ര
-റ
-ല
-ള
-ഴ
-വ
-ശ
-ഷ
-സ
-ഹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index dc4969143..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-ാ
-ി
-ീ
-ു
-ൂ
-ൃ
-െ
-േ
-ൈ
-ൊ
-ോ
-ൌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index c2a9f06e8..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-൦
-൧
-൨
-൩
-൪
-൫
-൬
-൭
-൮
-൯
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index d879c3b22..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-അ
-ആ
-ഇ
-ഈ
-ഉ
-ഊ
-ഋ
-ഌ
-എ
-ഏ
-ഐ
-ഒ
-ഓ
-ഔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 2c976a4a6..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ം
-ഃ
-്
-ൗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 105321587..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,254 +0,0 @@
-ക്ക
-ച്ച
-ട്ട
-ത്ത
-പ്പ
-ഗ്ഗ
-ജ്ജ
-ഡ്ഡ
-ദ്ദ
-ബ്ബ
-ങ്ങ
-ഞ്ഞ
-ണ്ണ
-ന്ന
-മ്മ
-യ്യ
-ല്ല
-വ്വ
-ശ്ശ
-സ്സ
-ള്ള
-റ്റ
-ക്ത
-ക്ഷ
-ഗ്ന
-ഗ്മ
-ങ്ക
-ച്ഛ
-ജ്ഞ
-ഞ്ച
-ണ്ട
-ണ്മ
-ത്ഥ
-ത്മ
-ത്ഭ
-ത്സ
-ദ്ധ
-ന്ത
-ന്ഥ
-ന്ദ
-ന്ധ
-ന്മ
-ന്റ
-മ്പ
-ബ്ദ
-ബ്ധ
-ശ്ച
-ഷ്ട
-സ്ഥ
-ഹ്ന
-ഹ്മ
-ക്യ
-ഖ്യ
-ഗ്യ
-ഘ്യ
-ങ്യ
-ച്യ
-ഛ്യ
-ജ്യ
-ഝ്യ
-ഞ്യ
-ട്യ
-ഠ്യ
-ഡ്യ
-ഢ്യ
-ണ്യ
-ത്യ
-ഥ്യ
-ദ്യ
-ധ്യ
-ന്യ
-പ്യ
-ഫ്യ
-ബ്യ
-ഭ്യ
-മ്യ
-ര്യ
-റ്യ
-ല്യ
-ള്യ
-ഴ്യ
-വ്യ
-ശ്യ
-ഷ്യ
-സ്യ
-ഹ്യ
-ക്ര
-ഖ്ര
-ഗ്ര
-ഘ്ര
-ച്ര
-ഛ്ര
-ജ്ര
-ട്ര
-ഠ്ര
-ഡ്ര
-ഢ്ര
-ത്ര
-ഥ്ര
-ദ്ര
-ധ്ര
-ന്ര
-പ്ര
-ഫ്ര
-ബ്ര
-ഭ്ര
-മ്ര
-ല്ര
-വ്ര
-ശ്ര
-ഷ്ര
-സ്ര
-ഹ്ര
-ക്ല
-ഖ്ല
-ഗ്ല
-ഘ്ല
-ങ്ല
-ച്ല
-ഛ്ല
-ജ്ല
-ഝ്ല
-ഞ്ല
-ട്ല
-ഠ്ല
-ഡ്ല
-ഢ്ല
-ണ്ല
-ത്ല
-ഥ്ല
-ദ്ല
-ധ്ല
-ന്ല
-പ്ല
-ഫ്ല
-ബ്ല
-ഭ്ല
-മ്ല
-യ്ല
-ര്ല
-റ്ല
-വ്ല
-ശ്ല
-ഷ്ല
-സ്ല
-ഹ്ല
-ക്ള
-ഖ്ള
-ഗ്ള
-ഘ്ള
-ങ്ള
-ച്ള
-ഛ്ള
-ജ്ള
-ഝ്ള
-ഞ്ള
-ട്ള
-ഠ്ള
-ഡ്ള
-ഢ്ള
-ണ്ള
-ത്ള
-ഥ്ള
-ദ്ള
-ധ്ള
-ന്ള
-പ്ള
-ഫ്ള
-ബ്ള
-ഭ്ള
-മ്ള
-യ്ള
-ര്ള
-റ്ള
-വ്ള
-ശ്ള
-ഷ്ള
-സ്ള
-ഹ്ള
-ക്വ
-ഖ്വ
-ഗ്വ
-ഘ്വ
-ങ്വ
-ച്വ
-ഛ്വ
-ജ്വ
-ഝ്വ
-ഞ്വ
-ട്വ
-ഠ്വ
-ഡ്വ
-ഢ്വ
-ണ്വ
-ത്വ
-ഥ്വ
-ദ്വ
-ധ്വ
-ന്വ
-പ്വ
-ഫ്വ
-ബ്വ
-ഭ്വ
-മ്വ
-ര്വ
-റ്വ
-ല്വ
-ള്വ
-ഴ്വ
-ശ്വ
-ഷ്വ
-സ്വ
-ഹ്വ
-ക്
-ഖ്
-ഗ്
-ഘ്
-ങ്
-ച്
-ഛ്
-ജ്
-ഝ്
-ഞ്
-ട്
-ഠ്
-ഡ്
-ഢ്
-ണ്
-ത്
-ഥ്
-ദ്
-ധ്
-ന്
-പ്
-ഫ്
-ബ്
-ഭ്
-മ്
-യ്
-ര്
-റ്
-ല്
-ള്
-ഴ്
-വ്
-ശ്
-ഷ്
-സ്
-ഹ്
-ഡ്രൈവ്
-അപ്ഡേറ്റ്
-അപ്ഗ്രേഡ്
-വ്യക്തം
-ഇന്‍സ്റ്റോള്‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
deleted file mode 100644
index 13de6eef0..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ମୁଁ
-ମୁଂ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
deleted file mode 100644
index 44a53dfe9..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-ஃ
-ஃக
-கூ
-கெ
-கொ
-கொ
-க்ஷ
-க்ஷொ
-க்ஷொ
-ஙூ
-சூ
-டி
-டீ
-டூ
-தூ
-மூ
-ரி
-ரீ
-ரூ
-ர்
-லி
-லீ
-କ୍ତ୍ର
-ତ୍ତ୍ବ
-ନ୍ତ୍ବ
-ନ୍ତ୍ର
-ନ୍ତ୍ର୍ଯ
-ସ୍ତ୍ର
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
deleted file mode 100644
index e8d24cb57..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ଆ ଅା
-ଐ ଏୗ
-ଔ ଓୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644
index c311f4222..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ଡ଼
-ଢ଼
-ୟ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index c15795c79..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ୠ
-ୡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 5692fa138..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-କ
-ଖ
-ଗ
-ଘ
-ଙ
-ଚ
-ଛ
-ଜ
-ଝ
-ଞ
-ଟ
-ଠ
-ଡ
-ଢ
-ଣ
-ତ
-ଥ
-ଦ
-ଧ
-ନ
-ପ
-ଫ
-ବ
-ଭ
-ମ
-ଯ
-ର
-ଲ
-ଳ
-ଵ
-ଶ
-ଷ
-ସ
-ହ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index d95d9093b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-ା
-ି
-ୀ
-ୁ
-ୂ
-ୃ
-େ
-ୈ
-ୋ
-ୌ
-ୖ
-ୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index ce7af5e06..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-୦
-୧
-୨
-୩
-୪
-୫
-୬
-୭
-୮
-୯
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 9d21b9d3c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-ଅ
-ଆ
-ଇ
-ଈ
-ଉ
-ଊ
-ଋ
-ଌ
-ଏ
-ଐ
-ଓ
-ଔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
deleted file mode 100644
index 6571b5271..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-୰
-ୱ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index ce411d25b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-ଁ
-ଂ
-ଃ
-଼
-ଽ
-୍
-ୖ
-ୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index fe110600e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,170 +0,0 @@
-କ୍ଷ
-ଙ୍କ
-ଙ୍ଖ
-ଙ୍ଗ
-ଙ୍ଘ
-ଙ୍ଳ
-ଙ୍କ୍ତ
-ଚ୍ଚ
-ଚ୍ଛ
-ଜ୍ଜ
-ଜ୍ଝ
-ଜ୍ଞ
-ଞ୍ଚ
-ଞ୍ଛ
-ଞ୍ଜ
-ଟ୍ଟ
-ଣ୍ଟ
-ଣ୍ଠ
-ଣ୍ଡ
-ଣ୍ଢ
-ଣ୍ଣ
-ତ୍କ
-ତ୍ତ
-ତ୍ଥ
-ତ୍ନ
-ତ୍ସ
-ତ୍ପ
-ଦ୍ଦ
-ଦ୍ଧ
-ଦ୍ଭ
-ଦ୍ଯ
-ବ୍ଡ
-ବ୍ଦ
-ବ୍ଧ
-ନ୍ତ
-ନ୍ତ୍ର
-ନ୍ଥ
-ନ୍ଦ
-ନ୍ଧ
-ନ୍ନ
-ଯ୍ତ
-ମ୍ପ
-ମ୍ଫ
-ମ୍ବ
-ମ୍ମ
-ମ୍ଭ
-ଶ୍ଚ
-ଶ୍ପ
-ଶ୍ଫ
-ଶ୍କ
-ଶ୍ଟ
-ଷ୍ଟ
-ଷ୍ଟ୍ବ
-ଷ୍ଠ
-ଷ୍ଣ
-ସ୍କ
-ସ୍ଖ
-ସ୍ଘ
-ସ୍ପ
-ସ୍ଫ
-ସ୍ତ
-ସ୍ତ୍ର
-ସ୍ଥ
-ସ୍ବ
-ସ୍ମୃ
-ହ୍ନ
-ହ୍ଳ
-ହ୍ଵ
-ପ୍ଟ
-କ୍କ
-କ୍ଖ
-କ୍ଗ
-କ୍ଘ
-କ୍ଚ
-କ୍ଛ
-କ୍ଜ
-କ୍ଝ
-କ୍ଟ
-କ୍ଠ
-କ୍ଡ
-କ୍ଢ
-କ୍ଣ
-କ୍ତ
-କ୍ଥ
-କ୍ଦ
-କ୍ଧ
-କ୍ନ
-କ୍ପ
-କ୍ଫ
-କ୍ବ
-କ୍ଭ
-କ୍ମ
-କ୍ଯ
-କ୍ର
-କ୍ଳ
-କ୍ଲ
-କ୍ହ
-ର୍କ
-ର୍ଖ
-ର୍ଗ
-ର୍ଘ
-ର୍ଚ
-ର୍ଚ୍ଚ
-ର୍ଚ୍ଛ
-ର୍ଛ
-ର୍ଜ
-ର୍ଝ
-ର୍ଟ
-ର୍ଠ
-ର୍ଡ
-ର୍ଢ
-ର୍ଣ
-ର୍ତ
-ର୍ତ୍ତ
-ର୍ଥ
-ର୍ଦ
-ର୍ଦ୍ଦ
-ର୍ଦ୍ଧ
-ର୍ଧ
-ର୍ନ
-ର୍ପ
-ର୍ଫ
-ର୍ବ
-ର୍ଭ
-ର୍ମ
-ର୍ଯ
-ର୍ଯ୍ଯ
-ର୍ଶ
-ର୍ଷ
-ର୍ସ
-ର୍ହ
-ର୍ଡ଼
-ର୍ଢ଼
-ଖ୍ର
-ଗ୍ର
-ଘ୍ର
-ଚ୍ଚ୍ର
-ଚ୍ଛ୍ର
-ଚ୍ର
-ଛ୍ର
-ଜ୍ର
-ଝ୍ର
-ଟ୍ର
-ଠ୍ର
-ଡ୍ର
-ଢ୍ର
-ଣ୍ର
-ତ୍ର
-ତ୍ତ୍ର
-ତ୍ଥ୍ର
-ଥ୍ର
-ଦ୍ର
-ଦ୍ଦ୍ର
-ଦ୍ଧ୍ର
-ଧ୍ର
-ନ୍ର
-ପ୍ର
-ଫ୍ର
-ବ୍ର
-ଭ୍ର
-ମ୍ର
-ଯ୍ର
-ଶ୍ର
-ଷ୍ର
-ସ୍ର
-ହ୍ର
-ଡ଼୍ର
-ଢ଼୍ର
-ଦ୍ଗ
-ତ୍ମ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
deleted file mode 100644
index 231a1f7a2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
+++ /dev/null
@@ -1,4390 +0,0 @@
-අ
-ආ
-ඇ
-ඈ
-ඉ
-ඊ
-උ
-ඌ
-ඍ
-ඎ
-ඏ
-ඐ
-එ
-ඒ
-ඓ
-ඔ
-ඕ
-ඖ
-ක
-කා
-කැ
-කෑ
-කි
-කී
-කු
-කූ
-කෘ
-කෲ
-කෟ
-කෳ
-කෙ
-කේ
-කෛ
-කො
-කෝ
-කෞ
-ක්
-කං
-කඃ
-ක්‍ර
-ක්‍රා
-ක්‍රැ
-ක්‍රෑ
-ක්‍රි
-ක්‍රී
-ක්‍රු
-ක්‍රූ
-ක්‍රෘ
-ක්‍රෲ
-ක්‍රෟ
-ක්‍රෳ
-ක්‍රෙ
-ක්‍රේ
-ක්‍රෛ
-ක්‍රො
-ක්‍රෝ
-ක්‍රෞ
-ක්‍ර්
-ක්‍රං
-ක්‍රඃ
-ක්‍ය
-ක්‍යා
-ක්‍යැ
-ක්‍යෑ
-ක්‍යි
-ක්‍යී
-ක්‍යු
-ක්‍යූ
-ක්‍යෘ
-ක්‍යෲ
-ක්‍යෟ
-ක්‍යෳ
-ක්‍යෙ
-ක්‍යේ
-ක්‍යෛ
-ක්‍යො
-ක්‍යෝ
-ක්‍යෞ
-ක්‍ය්
-ක්‍යං
-ක්‍යඃ
-ර්‍ක
-ර්‍කා
-ර්‍කැ
-ර්‍කෑ
-ර්‍කි
-ර්‍කී
-ර්‍කු
-ර්‍කූ
-ර්‍කෘ
-ර්‍කෲ
-ර්‍කෟ
-ර්‍කෳ
-ර්‍කෙ
-ර්‍කේ
-ර්‍කෛ
-ර්‍කො
-ර්‍කෝ
-ර්‍කෞ
-ර්‍ක්
-ර්‍කං
-ර්‍කඃ
-ඛ
-ඛා
-ඛැ
-ඛෑ
-ඛි
-ඛී
-ඛු
-ඛූ
-ඛෘ
-ඛෲ
-ඛෟ
-ඛෳ
-ඛෙ
-ඛේ
-ඛෛ
-ඛො
-ඛෝ
-ඛෞ
-ඛ්
-ඛං
-ඛඃ
-ඛ්‍ර
-ඛ්‍රා
-ඛ්‍රැ
-ඛ්‍රෑ
-ඛ්‍රි
-ඛ්‍රී
-ඛ්‍රු
-ඛ්‍රූ
-ඛ්‍රෘ
-ඛ්‍රෲ
-ඛ්‍රෟ
-ඛ්‍රෳ
-ඛ්‍රෙ
-ඛ්‍රේ
-ඛ්‍රෛ
-ඛ්‍රො
-ඛ්‍රෝ
-ඛ්‍රෞ
-ඛ්‍ර්
-ඛ්‍රං
-ඛ්‍රඃ
-ඛ්‍ය
-ඛ්‍යා
-ඛ්‍යැ
-ඛ්‍යෑ
-ඛ්‍යි
-ඛ්‍යී
-ඛ්‍යු
-ඛ්‍යූ
-ඛ්‍යෘ
-ඛ්‍යෲ
-ඛ්‍යෟ
-ඛ්‍යෳ
-ඛ්‍යෙ
-ඛ්‍යේ
-ඛ්‍යෛ
-ඛ්‍යො
-ඛ්‍යෝ
-ඛ්‍යෞ
-ඛ්‍ය්
-ඛ්‍යං
-ඛ්‍යඃ
-ර්‍ඛ
-ර්‍ඛා
-ර්‍ඛැ
-ර්‍ඛෑ
-ර්‍ඛි
-ර්‍ඛී
-ර්‍ඛු
-ර්‍ඛූ
-ර්‍ඛෘ
-ර්‍ඛෲ
-ර්‍ඛෟ
-ර්‍ඛෳ
-ර්‍ඛෙ
-ර්‍ඛේ
-ර්‍ඛෛ
-ර්‍ඛො
-ර්‍ඛෝ
-ර්‍ඛෞ
-ර්‍ඛ්
-ර්‍ඛං
-ර්‍ඛඃ
-ග
-ගා
-ගැ
-ගෑ
-ගි
-ගී
-ගු
-ගූ
-ගෘ
-ගෲ
-ගෟ
-ගෳ
-ගෙ
-ගේ
-ගෛ
-ගො
-ගෝ
-ගෞ
-ග්
-ගං
-ගඃ
-ග්‍ර
-ග්‍රා
-ග්‍රැ
-ග්‍රෑ
-ග්‍රි
-ග්‍රී
-ග්‍රු
-ග්‍රූ
-ග්‍රෘ
-ග්‍රෲ
-ග්‍රෟ
-ග්‍රෳ
-ග්‍රෙ
-ග්‍රේ
-ග්‍රෛ
-ග්‍රො
-ග්‍රෝ
-ග්‍රෞ
-ග්‍ර්
-ග්‍රං
-ග්‍රඃ
-ග්‍ය
-ග්‍යා
-ග්‍යැ
-ග්‍යෑ
-ග්‍යි
-ග්‍යී
-ග්‍යු
-ග්‍යූ
-ග්‍යෘ
-ග්‍යෲ
-ග්‍යෟ
-ග්‍යෳ
-ග්‍යෙ
-ග්‍යේ
-ග්‍යෛ
-ග්‍යො
-ග්‍යෝ
-ග්‍යෞ
-ග්‍ය්
-ග්‍යං
-ග්‍යඃ
-ර්‍ග
-ර්‍ගා
-ර්‍ගැ
-ර්‍ගෑ
-ර්‍ගි
-ර්‍ගී
-ර්‍ගු
-ර්‍ගූ
-ර්‍ගෘ
-ර්‍ගෲ
-ර්‍ගෟ
-ර්‍ගෳ
-ර්‍ගෙ
-ර්‍ගේ
-ර්‍ගෛ
-ර්‍ගො
-ර්‍ගෝ
-ර්‍ගෞ
-ර්‍ග්
-ර්‍ගං
-ර්‍ගඃ
-ඝ
-ඝා
-ඝැ
-ඝෑ
-ඝි
-ඝී
-ඝු
-ඝූ
-ඝෘ
-ඝෲ
-ඝෟ
-ඝෳ
-ඝෙ
-ඝේ
-ඝෛ
-ඝො
-ඝෝ
-ඝෞ
-ඝ්
-ඝං
-ඝඃ
-ඝ්‍ර
-ඝ්‍රා
-ඝ්‍රැ
-ඝ්‍රෑ
-ඝ්‍රි
-ඝ්‍රී
-ඝ්‍රු
-ඝ්‍රූ
-ඝ්‍රෘ
-ඝ්‍රෲ
-ඝ්‍රෟ
-ඝ්‍රෳ
-ඝ්‍රෙ
-ඝ්‍රේ
-ඝ්‍රෛ
-ඝ්‍රො
-ඝ්‍රෝ
-ඝ්‍රෞ
-ඝ්‍ර්
-ඝ්‍රං
-ඝ්‍රඃ
-ඝ්‍ය
-ඝ්‍යා
-ඝ්‍යැ
-ඝ්‍යෑ
-ඝ්‍යි
-ඝ්‍යී
-ඝ්‍යු
-ඝ්‍යූ
-ඝ්‍යෘ
-ඝ්‍යෲ
-ඝ්‍යෟ
-ඝ්‍යෳ
-ඝ්‍යෙ
-ඝ්‍යේ
-ඝ්‍යෛ
-ඝ්‍යො
-ඝ්‍යෝ
-ඝ්‍යෞ
-ඝ්‍ය්
-ඝ්‍යං
-ඝ්‍යඃ
-ර්‍ඝ
-ර්‍ඝා
-ර්‍ඝැ
-ර්‍ඝෑ
-ර්‍ඝි
-ර්‍ඝී
-ර්‍ඝු
-ර්‍ඝූ
-ර්‍ඝෘ
-ර්‍ඝෲ
-ර්‍ඝෟ
-ර්‍ඝෳ
-ර්‍ඝෙ
-ර්‍ඝේ
-ර්‍ඝෛ
-ර්‍ඝො
-ර්‍ඝෝ
-ර්‍ඝෞ
-ර්‍ඝ්
-ර්‍ඝං
-ර්‍ඝඃ
-ඞ
-ඞා
-ඞැ
-ඞෑ
-ඞි
-ඞී
-ඞු
-ඞූ
-ඞෘ
-ඞෲ
-ඞෟ
-ඞෳ
-ඞෙ
-ඞේ
-ඞෛ
-ඞො
-ඞෝ
-ඞෞ
-ඞ්
-ඞං
-ඞඃ
-ඞ්‍ර
-ඞ්‍රා
-ඞ්‍රැ
-ඞ්‍රෑ
-ඞ්‍රි
-ඞ්‍රී
-ඞ්‍රු
-ඞ්‍රූ
-ඞ්‍රෘ
-ඞ්‍රෲ
-ඞ්‍රෟ
-ඞ්‍රෳ
-ඞ්‍රෙ
-ඞ්‍රේ
-ඞ්‍රෛ
-ඞ්‍රො
-ඞ්‍රෝ
-ඞ්‍රෞ
-ඞ්‍ර්
-ඞ්‍රං
-ඞ්‍රඃ
-ඞ්‍ය
-ඞ්‍යා
-ඞ්‍යැ
-ඞ්‍යෑ
-ඞ්‍යි
-ඞ්‍යී
-ඞ්‍යු
-ඞ්‍යූ
-ඞ්‍යෘ
-ඞ්‍යෲ
-ඞ්‍යෟ
-ඞ්‍යෳ
-ඞ්‍යෙ
-ඞ්‍යේ
-ඞ්‍යෛ
-ඞ්‍යො
-ඞ්‍යෝ
-ඞ්‍යෞ
-ඞ්‍ය්
-ඞ්‍යං
-ඞ්‍යඃ
-ර්‍ඞ
-ර්‍ඞා
-ර්‍ඞැ
-ර්‍ඞෑ
-ර්‍ඞි
-ර්‍ඞී
-ර්‍ඞු
-ර්‍ඞූ
-ර්‍ඞෘ
-ර්‍ඞෲ
-ර්‍ඞෟ
-ර්‍ඞෳ
-ර්‍ඞෙ
-ර්‍ඞේ
-ර්‍ඞෛ
-ර්‍ඞො
-ර්‍ඞෝ
-ර්‍ඞෞ
-ර්‍ඞ්
-ර්‍ඞං
-ර්‍ඞඃ
-ඟ
-ඟා
-ඟැ
-ඟෑ
-ඟි
-ඟී
-ඟු
-ඟූ
-ඟෘ
-ඟෲ
-ඟෟ
-ඟෳ
-ඟෙ
-ඟේ
-ඟෛ
-ඟො
-ඟෝ
-ඟෞ
-ඟ්
-ඟං
-ඟඃ
-ඟ්‍ර
-ඟ්‍රා
-ඟ්‍රැ
-ඟ්‍රෑ
-ඟ්‍රි
-ඟ්‍රී
-ඟ්‍රු
-ඟ්‍රූ
-ඟ්‍රෘ
-ඟ්‍රෲ
-ඟ්‍රෟ
-ඟ්‍රෳ
-ඟ්‍රෙ
-ඟ්‍රේ
-ඟ්‍රෛ
-ඟ්‍රො
-ඟ්‍රෝ
-ඟ්‍රෞ
-ඟ්‍ර්
-ඟ්‍රං
-ඟ්‍රඃ
-ඟ්‍ය
-ඟ්‍යා
-ඟ්‍යැ
-ඟ්‍යෑ
-ඟ්‍යි
-ඟ්‍යී
-ඟ්‍යු
-ඟ්‍යූ
-ඟ්‍යෘ
-ඟ්‍යෲ
-ඟ්‍යෟ
-ඟ්‍යෳ
-ඟ්‍යෙ
-ඟ්‍යේ
-ඟ්‍යෛ
-ඟ්‍යො
-ඟ්‍යෝ
-ඟ්‍යෞ
-ඟ්‍ය්
-ඟ්‍යං
-ඟ්‍යඃ
-ර්‍ඟ
-ර්‍ඟා
-ර්‍ඟැ
-ර්‍ඟෑ
-ර්‍ඟි
-ර්‍ඟී
-ර්‍ඟු
-ර්‍ඟූ
-ර්‍ඟෘ
-ර්‍ඟෲ
-ර්‍ඟෟ
-ර්‍ඟෳ
-ර්‍ඟෙ
-ර්‍ඟේ
-ර්‍ඟෛ
-ර්‍ඟො
-ර්‍ඟෝ
-ර්‍ඟෞ
-ර්‍ඟ්
-ර්‍ඟං
-ර්‍ඟඃ
-ච
-චා
-චැ
-චෑ
-චි
-චී
-චු
-චූ
-චෘ
-චෲ
-චෟ
-චෳ
-චෙ
-චේ
-චෛ
-චො
-චෝ
-චෞ
-ච්
-චං
-චඃ
-ච්‍ර
-ච්‍රා
-ච්‍රැ
-ච්‍රෑ
-ච්‍රි
-ච්‍රී
-ච්‍රු
-ච්‍රූ
-ච්‍රෘ
-ච්‍රෲ
-ච්‍රෟ
-ච්‍රෳ
-ච්‍රෙ
-ච්‍රේ
-ච්‍රෛ
-ච්‍රො
-ච්‍රෝ
-ච්‍රෞ
-ච්‍ර්
-ච්‍රං
-ච්‍රඃ
-ච්‍ය
-ච්‍යා
-ච්‍යැ
-ච්‍යෑ
-ච්‍යි
-ච්‍යී
-ච්‍යු
-ච්‍යූ
-ච්‍යෘ
-ච්‍යෲ
-ච්‍යෟ
-ච්‍යෳ
-ච්‍යෙ
-ච්‍යේ
-ච්‍යෛ
-ච්‍යො
-ච්‍යෝ
-ච්‍යෞ
-ච්‍ය්
-ච්‍යං
-ච්‍යඃ
-ර්‍ච
-ර්‍චා
-ර්‍චැ
-ර්‍චෑ
-ර්‍චි
-ර්‍චී
-ර්‍චු
-ර්‍චූ
-ර්‍චෘ
-ර්‍චෲ
-ර්‍චෟ
-ර්‍චෳ
-ර්‍චෙ
-ර්‍චේ
-ර්‍චෛ
-ර්‍චො
-ර්‍චෝ
-ර්‍චෞ
-ර්‍ච්
-ර්‍චං
-ර්‍චඃ
-ඡ
-ඡා
-ඡැ
-ඡෑ
-ඡි
-ඡී
-ඡු
-ඡූ
-ඡෘ
-ඡෲ
-ඡෟ
-ඡෳ
-ඡෙ
-ඡේ
-ඡෛ
-ඡො
-ඡෝ
-ඡෞ
-ඡ්
-ඡං
-ඡඃ
-ඡ්‍ර
-ඡ්‍රා
-ඡ්‍රැ
-ඡ්‍රෑ
-ඡ්‍රි
-ඡ්‍රී
-ඡ්‍රු
-ඡ්‍රූ
-ඡ්‍රෘ
-ඡ්‍රෲ
-ඡ්‍රෟ
-ඡ්‍රෳ
-ඡ්‍රෙ
-ඡ්‍රේ
-ඡ්‍රෛ
-ඡ්‍රො
-ඡ්‍රෝ
-ඡ්‍රෞ
-ඡ්‍ර්
-ඡ්‍රං
-ඡ්‍රඃ
-ඡ්‍ය
-ඡ්‍යා
-ඡ්‍යැ
-ඡ්‍යෑ
-ඡ්‍යි
-ඡ්‍යී
-ඡ්‍යු
-ඡ්‍යූ
-ඡ්‍යෘ
-ඡ්‍යෲ
-ඡ්‍යෟ
-ඡ්‍යෳ
-ඡ්‍යෙ
-ඡ්‍යේ
-ඡ්‍යෛ
-ඡ්‍යො
-ඡ්‍යෝ
-ඡ්‍යෞ
-ඡ්‍ය්
-ඡ්‍යං
-ඡ්‍යඃ
-ර්‍ඡ
-ර්‍ඡා
-ර්‍ඡැ
-ර්‍ඡෑ
-ර්‍ඡි
-ර්‍ඡී
-ර්‍ඡු
-ර්‍ඡූ
-ර්‍ඡෘ
-ර්‍ඡෲ
-ර්‍ඡෟ
-ර්‍ඡෳ
-ර්‍ඡෙ
-ර්‍ඡේ
-ර්‍ඡෛ
-ර්‍ඡො
-ර්‍ඡෝ
-ර්‍ඡෞ
-ර්‍ඡ්
-ර්‍ඡං
-ර්‍ඡඃ
-ජ
-ජා
-ජැ
-ජෑ
-ජි
-ජී
-ජු
-ජූ
-ජෘ
-ජෲ
-ජෟ
-ජෳ
-ජෙ
-ජේ
-ජෛ
-ජො
-ජෝ
-ජෞ
-ජ්
-ජං
-ජඃ
-ජ්‍ර
-ජ්‍රා
-ජ්‍රැ
-ජ්‍රෑ
-ජ්‍රි
-ජ්‍රී
-ජ්‍රු
-ජ්‍රූ
-ජ්‍රෘ
-ජ්‍රෲ
-ජ්‍රෟ
-ජ්‍රෳ
-ජ්‍රෙ
-ජ්‍රේ
-ජ්‍රෛ
-ජ්‍රො
-ජ්‍රෝ
-ජ්‍රෞ
-ජ්‍ර්
-ජ්‍රං
-ජ්‍රඃ
-ජ්‍ය
-ජ්‍යා
-ජ්‍යැ
-ජ්‍යෑ
-ජ්‍යි
-ජ්‍යී
-ජ්‍යු
-ජ්‍යූ
-ජ්‍යෘ
-ජ්‍යෲ
-ජ්‍යෟ
-ජ්‍යෳ
-ජ්‍යෙ
-ජ්‍යේ
-ජ්‍යෛ
-ජ්‍යො
-ජ්‍යෝ
-ජ්‍යෞ
-ජ්‍ය්
-ජ්‍යං
-ජ්‍යඃ
-ර්‍ජ
-ර්‍ජා
-ර්‍ජැ
-ර්‍ජෑ
-ර්‍ජි
-ර්‍ජී
-ර්‍ජු
-ර්‍ජූ
-ර්‍ජෘ
-ර්‍ජෲ
-ර්‍ජෟ
-ර්‍ජෳ
-ර්‍ජෙ
-ර්‍ජේ
-ර්‍ජෛ
-ර්‍ජො
-ර්‍ජෝ
-ර්‍ජෞ
-ර්‍ජ්
-ර්‍ජං
-ර්‍ජඃ
-ඣ
-ඣා
-ඣැ
-ඣෑ
-ඣි
-ඣී
-ඣු
-ඣූ
-ඣෘ
-ඣෲ
-ඣෟ
-ඣෳ
-ඣෙ
-ඣේ
-ඣෛ
-ඣො
-ඣෝ
-ඣෞ
-ඣ්
-ඣං
-ඣඃ
-ඣ්‍ර
-ඣ්‍රා
-ඣ්‍රැ
-ඣ්‍රෑ
-ඣ්‍රි
-ඣ්‍රී
-ඣ්‍රු
-ඣ්‍රූ
-ඣ්‍රෘ
-ඣ්‍රෲ
-ඣ්‍රෟ
-ඣ්‍රෳ
-ඣ්‍රෙ
-ඣ්‍රේ
-ඣ්‍රෛ
-ඣ්‍රො
-ඣ්‍රෝ
-ඣ්‍රෞ
-ඣ්‍ර්
-ඣ්‍රං
-ඣ්‍රඃ
-ඣ්‍ය
-ඣ්‍යා
-ඣ්‍යැ
-ඣ්‍යෑ
-ඣ්‍යි
-ඣ්‍යී
-ඣ්‍යු
-ඣ්‍යූ
-ඣ්‍යෘ
-ඣ්‍යෲ
-ඣ්‍යෟ
-ඣ්‍යෳ
-ඣ්‍යෙ
-ඣ්‍යේ
-ඣ්‍යෛ
-ඣ්‍යො
-ඣ්‍යෝ
-ඣ්‍යෞ
-ඣ්‍ය්
-ඣ්‍යං
-ඣ්‍යඃ
-ර්‍ඣ
-ර්‍ඣා
-ර්‍ඣැ
-ර්‍ඣෑ
-ර්‍ඣි
-ර්‍ඣී
-ර්‍ඣු
-ර්‍ඣූ
-ර්‍ඣෘ
-ර්‍ඣෲ
-ර්‍ඣෟ
-ර්‍ඣෳ
-ර්‍ඣෙ
-ර්‍ඣේ
-ර්‍ඣෛ
-ර්‍ඣො
-ර්‍ඣෝ
-ර්‍ඣෞ
-ර්‍ඣ්
-ර්‍ඣං
-ර්‍ඣඃ
-ඥ
-ඥා
-ඥැ
-ඥෑ
-ඥි
-ඥී
-ඥු
-ඥූ
-ඥෘ
-ඥෲ
-ඥෟ
-ඥෳ
-ඥෙ
-ඥේ
-ඥෛ
-ඥො
-ඥෝ
-ඥෞ
-ඥ්
-ඥං
-ඥඃ
-ඥ්‍ර
-ඥ්‍රා
-ඥ්‍රැ
-ඥ්‍රෑ
-ඥ්‍රි
-ඥ්‍රී
-ඥ්‍රු
-ඥ්‍රූ
-ඥ්‍රෘ
-ඥ්‍රෲ
-ඥ්‍රෟ
-ඥ්‍රෳ
-ඥ්‍රෙ
-ඥ්‍රේ
-ඥ්‍රෛ
-ඥ්‍රො
-ඥ්‍රෝ
-ඥ්‍රෞ
-ඥ්‍ර්
-ඥ්‍රං
-ඥ්‍රඃ
-ඥ්‍ය
-ඥ්‍යා
-ඥ්‍යැ
-ඥ්‍යෑ
-ඥ්‍යි
-ඥ්‍යී
-ඥ්‍යු
-ඥ්‍යූ
-ඥ්‍යෘ
-ඥ්‍යෲ
-ඥ්‍යෟ
-ඥ්‍යෳ
-ඥ්‍යෙ
-ඥ්‍යේ
-ඥ්‍යෛ
-ඥ්‍යො
-ඥ්‍යෝ
-ඥ්‍යෞ
-ඥ්‍ය්
-ඥ්‍යං
-ඥ්‍යඃ
-ර්‍ඥ
-ර්‍ඥා
-ර්‍ඥැ
-ර්‍ඥෑ
-ර්‍ඥි
-ර්‍ඥී
-ර්‍ඥු
-ර්‍ඥූ
-ර්‍ඥෘ
-ර්‍ඥෲ
-ර්‍ඥෟ
-ර්‍ඥෳ
-ර්‍ඥෙ
-ර්‍ඥේ
-ර්‍ඥෛ
-ර්‍ඥො
-ර්‍ඥෝ
-ර්‍ඥෞ
-ර්‍ඥ්
-ර්‍ඥං
-ර්‍ඥඃ
-ඤ
-ඤා
-ඤැ
-ඤෑ
-ඤි
-ඤී
-ඤු
-ඤූ
-ඤෘ
-ඤෲ
-ඤෟ
-ඤෳ
-ඤෙ
-ඤේ
-ඤෛ
-ඤො
-ඤෝ
-ඤෞ
-ඤ්
-ඤං
-ඤඃ
-ඤ්‍ර
-ඤ්‍රා
-ඤ්‍රැ
-ඤ්‍රෑ
-ඤ්‍රි
-ඤ්‍රී
-ඤ්‍රු
-ඤ්‍රූ
-ඤ්‍රෘ
-ඤ්‍රෲ
-ඤ්‍රෟ
-ඤ්‍රෳ
-ඤ්‍රෙ
-ඤ්‍රේ
-ඤ්‍රෛ
-ඤ්‍රො
-ඤ්‍රෝ
-ඤ්‍රෞ
-ඤ්‍ර්
-ඤ්‍රං
-ඤ්‍රඃ
-ඤ්‍ය
-ඤ්‍යා
-ඤ්‍යැ
-ඤ්‍යෑ
-ඤ්‍යි
-ඤ්‍යී
-ඤ්‍යු
-ඤ්‍යූ
-ඤ්‍යෘ
-ඤ්‍යෲ
-ඤ්‍යෟ
-ඤ්‍යෳ
-ඤ්‍යෙ
-ඤ්‍යේ
-ඤ්‍යෛ
-ඤ්‍යො
-ඤ්‍යෝ
-ඤ්‍යෞ
-ඤ්‍ය්
-ඤ්‍යං
-ඤ්‍යඃ
-ර්‍ඤ
-ර්‍ඤා
-ර්‍ඤැ
-ර්‍ඤෑ
-ර්‍ඤි
-ර්‍ඤී
-ර්‍ඤු
-ර්‍ඤූ
-ර්‍ඤෘ
-ර්‍ඤෲ
-ර්‍ඤෟ
-ර්‍ඤෳ
-ර්‍ඤෙ
-ර්‍ඤේ
-ර්‍ඤෛ
-ර්‍ඤො
-ර්‍ඤෝ
-ර්‍ඤෞ
-ර්‍ඤ්
-ර්‍ඤං
-ර්‍ඤඃ
-ඦ
-ඦා
-ඦැ
-ඦෑ
-ඦි
-ඦී
-ඦු
-ඦූ
-ඦෘ
-ඦෲ
-ඦෟ
-ඦෳ
-ඦෙ
-ඦේ
-ඦෛ
-ඦො
-ඦෝ
-ඦෞ
-ඦ්
-ඦං
-ඦඃ
-ඦ්‍ර
-ඦ්‍රා
-ඦ්‍රැ
-ඦ්‍රෑ
-ඦ්‍රි
-ඦ්‍රී
-ඦ්‍රු
-ඦ්‍රූ
-ඦ්‍රෘ
-ඦ්‍රෲ
-ඦ්‍රෟ
-ඦ්‍රෳ
-ඦ්‍රෙ
-ඦ්‍රේ
-ඦ්‍රෛ
-ඦ්‍රො
-ඦ්‍රෝ
-ඦ්‍රෞ
-ඦ්‍ර්
-ඦ්‍රං
-ඦ්‍රඃ
-ඦ්‍ය
-ඦ්‍යා
-ඦ්‍යැ
-ඦ්‍යෑ
-ඦ්‍යි
-ඦ්‍යී
-ඦ්‍යු
-ඦ්‍යූ
-ඦ්‍යෘ
-ඦ්‍යෲ
-ඦ්‍යෟ
-ඦ්‍යෳ
-ඦ්‍යෙ
-ඦ්‍යේ
-ඦ්‍යෛ
-ඦ්‍යො
-ඦ්‍යෝ
-ඦ්‍යෞ
-ඦ්‍ය්
-ඦ්‍යං
-ඦ්‍යඃ
-ර්‍ඦ
-ර්‍ඦා
-ර්‍ඦැ
-ර්‍ඦෑ
-ර්‍ඦි
-ර්‍ඦී
-ර්‍ඦු
-ර්‍ඦූ
-ර්‍ඦෘ
-ර්‍ඦෲ
-ර්‍ඦෟ
-ර්‍ඦෳ
-ර්‍ඦෙ
-ර්‍ඦේ
-ර්‍ඦෛ
-ර්‍ඦො
-ර්‍ඦෝ
-ර්‍ඦෞ
-ර්‍ඦ්
-ර්‍ඦං
-ර්‍ඦඃ
-ට
-ටා
-ටැ
-ටෑ
-ටි
-ටී
-ටු
-ටූ
-ටෘ
-ටෲ
-ටෟ
-ටෳ
-ටෙ
-ටේ
-ටෛ
-ටො
-ටෝ
-ටෞ
-ට්
-ටං
-ටඃ
-ට්‍ර
-ට්‍රා
-ට්‍රැ
-ට්‍රෑ
-ට්‍රි
-ට්‍රී
-ට්‍රු
-ට්‍රූ
-ට්‍රෘ
-ට්‍රෲ
-ට්‍රෟ
-ට්‍රෳ
-ට්‍රෙ
-ට්‍රේ
-ට්‍රෛ
-ට්‍රො
-ට්‍රෝ
-ට්‍රෞ
-ට්‍ර්
-ට්‍රං
-ට්‍රඃ
-ට්‍ය
-ට්‍යා
-ට්‍යැ
-ට්‍යෑ
-ට්‍යි
-ට්‍යී
-ට්‍යු
-ට්‍යූ
-ට්‍යෘ
-ට්‍යෲ
-ට්‍යෟ
-ට්‍යෳ
-ට්‍යෙ
-ට්‍යේ
-ට්‍යෛ
-ට්‍යො
-ට්‍යෝ
-ට්‍යෞ
-ට්‍ය්
-ට්‍යං
-ට්‍යඃ
-ර්‍ට
-ර්‍ටා
-ර්‍ටැ
-ර්‍ටෑ
-ර්‍ටි
-ර්‍ටී
-ර්‍ටු
-ර්‍ටූ
-ර්‍ටෘ
-ර්‍ටෲ
-ර්‍ටෟ
-ර්‍ටෳ
-ර්‍ටෙ
-ර්‍ටේ
-ර්‍ටෛ
-ර්‍ටො
-ර්‍ටෝ
-ර්‍ටෞ
-ර්‍ට්
-ර්‍ටං
-ර්‍ටඃ
-ඨ
-ඨා
-ඨැ
-ඨෑ
-ඨි
-ඨී
-ඨු
-ඨූ
-ඨෘ
-ඨෲ
-ඨෟ
-ඨෳ
-ඨෙ
-ඨේ
-ඨෛ
-ඨො
-ඨෝ
-ඨෞ
-ඨ්
-ඨං
-ඨඃ
-ඨ්‍ර
-ඨ්‍රා
-ඨ්‍රැ
-ඨ්‍රෑ
-ඨ්‍රි
-ඨ්‍රී
-ඨ්‍රු
-ඨ්‍රූ
-ඨ්‍රෘ
-ඨ්‍රෲ
-ඨ්‍රෟ
-ඨ්‍රෳ
-ඨ්‍රෙ
-ඨ්‍රේ
-ඨ්‍රෛ
-ඨ්‍රො
-ඨ්‍රෝ
-ඨ්‍රෞ
-ඨ්‍ර්
-ඨ්‍රං
-ඨ්‍රඃ
-ඨ්‍ය
-ඨ්‍යා
-ඨ්‍යැ
-ඨ්‍යෑ
-ඨ්‍යි
-ඨ්‍යී
-ඨ්‍යු
-ඨ්‍යූ
-ඨ්‍යෘ
-ඨ්‍යෲ
-ඨ්‍යෟ
-ඨ්‍යෳ
-ඨ්‍යෙ
-ඨ්‍යේ
-ඨ්‍යෛ
-ඨ්‍යො
-ඨ්‍යෝ
-ඨ්‍යෞ
-ඨ්‍ය්
-ඨ්‍යං
-ඨ්‍යඃ
-ර්‍ඨ
-ර්‍ඨා
-ර්‍ඨැ
-ර්‍ඨෑ
-ර්‍ඨි
-ර්‍ඨී
-ර්‍ඨු
-ර්‍ඨූ
-ර්‍ඨෘ
-ර්‍ඨෲ
-ර්‍ඨෟ
-ර්‍ඨෳ
-ර්‍ඨෙ
-ර්‍ඨේ
-ර්‍ඨෛ
-ර්‍ඨො
-ර්‍ඨෝ
-ර්‍ඨෞ
-ර්‍ඨ්
-ර්‍ඨං
-ර්‍ඨඃ
-ඩ
-ඩා
-ඩැ
-ඩෑ
-ඩි
-ඩී
-ඩු
-ඩූ
-ඩෘ
-ඩෲ
-ඩෟ
-ඩෳ
-ඩෙ
-ඩේ
-ඩෛ
-ඩො
-ඩෝ
-ඩෞ
-ඩ්
-ඩං
-ඩඃ
-ඩ්‍ර
-ඩ්‍රා
-ඩ්‍රැ
-ඩ්‍රෑ
-ඩ්‍රි
-ඩ්‍රී
-ඩ්‍රු
-ඩ්‍රූ
-ඩ්‍රෘ
-ඩ්‍රෲ
-ඩ්‍රෟ
-ඩ්‍රෳ
-ඩ්‍රෙ
-ඩ්‍රේ
-ඩ්‍රෛ
-ඩ්‍රො
-ඩ්‍රෝ
-ඩ්‍රෞ
-ඩ්‍ර්
-ඩ්‍රං
-ඩ්‍රඃ
-ඩ්‍ය
-ඩ්‍යා
-ඩ්‍යැ
-ඩ්‍යෑ
-ඩ්‍යි
-ඩ්‍යී
-ඩ්‍යු
-ඩ්‍යූ
-ඩ්‍යෘ
-ඩ්‍යෲ
-ඩ්‍යෟ
-ඩ්‍යෳ
-ඩ්‍යෙ
-ඩ්‍යේ
-ඩ්‍යෛ
-ඩ්‍යො
-ඩ්‍යෝ
-ඩ්‍යෞ
-ඩ්‍ය්
-ඩ්‍යං
-ඩ්‍යඃ
-ර්‍ඩ
-ර්‍ඩා
-ර්‍ඩැ
-ර්‍ඩෑ
-ර්‍ඩි
-ර්‍ඩී
-ර්‍ඩු
-ර්‍ඩූ
-ර්‍ඩෘ
-ර්‍ඩෲ
-ර්‍ඩෟ
-ර්‍ඩෳ
-ර්‍ඩෙ
-ර්‍ඩේ
-ර්‍ඩෛ
-ර්‍ඩො
-ර්‍ඩෝ
-ර්‍ඩෞ
-ර්‍ඩ්
-ර්‍ඩං
-ර්‍ඩඃ
-ඪ
-ඪා
-ඪැ
-ඪෑ
-ඪි
-ඪී
-ඪු
-ඪූ
-ඪෘ
-ඪෲ
-ඪෟ
-ඪෳ
-ඪෙ
-ඪේ
-ඪෛ
-ඪො
-ඪෝ
-ඪෞ
-ඪ්
-ඪං
-ඪඃ
-ඪ්‍ර
-ඪ්‍රා
-ඪ්‍රැ
-ඪ්‍රෑ
-ඪ්‍රි
-ඪ්‍රී
-ඪ්‍රු
-ඪ්‍රූ
-ඪ්‍රෘ
-ඪ්‍රෲ
-ඪ්‍රෟ
-ඪ්‍රෳ
-ඪ්‍රෙ
-ඪ්‍රේ
-ඪ්‍රෛ
-ඪ්‍රො
-ඪ්‍රෝ
-ඪ්‍රෞ
-ඪ්‍ර්
-ඪ්‍රං
-ඪ්‍රඃ
-ඪ්‍ය
-ඪ්‍යා
-ඪ්‍යැ
-ඪ්‍යෑ
-ඪ්‍යි
-ඪ්‍යී
-ඪ්‍යු
-ඪ්‍යූ
-ඪ්‍යෘ
-ඪ්‍යෲ
-ඪ්‍යෟ
-ඪ්‍යෳ
-ඪ්‍යෙ
-ඪ්‍යේ
-ඪ්‍යෛ
-ඪ්‍යො
-ඪ්‍යෝ
-ඪ්‍යෞ
-ඪ්‍ය්
-ඪ්‍යං
-ඪ්‍යඃ
-ර්‍ඪ
-ර්‍ඪා
-ර්‍ඪැ
-ර්‍ඪෑ
-ර්‍ඪි
-ර්‍ඪී
-ර්‍ඪු
-ර්‍ඪූ
-ර්‍ඪෘ
-ර්‍ඪෲ
-ර්‍ඪෟ
-ර්‍ඪෳ
-ර්‍ඪෙ
-ර්‍ඪේ
-ර්‍ඪෛ
-ර්‍ඪො
-ර්‍ඪෝ
-ර්‍ඪෞ
-ර්‍ඪ්
-ර්‍ඪං
-ර්‍ඪඃ
-ණ
-ණා
-ණැ
-ණෑ
-ණි
-ණී
-ණු
-ණූ
-ණෘ
-ණෲ
-ණෟ
-ණෳ
-ණෙ
-ණේ
-ණෛ
-ණො
-ණෝ
-ණෞ
-ණ්
-ණං
-ණඃ
-ණ්‍ර
-ණ්‍රා
-ණ්‍රැ
-ණ්‍රෑ
-ණ්‍රි
-ණ්‍රී
-ණ්‍රු
-ණ්‍රූ
-ණ්‍රෘ
-ණ්‍රෲ
-ණ්‍රෟ
-ණ්‍රෳ
-ණ්‍රෙ
-ණ්‍රේ
-ණ්‍රෛ
-ණ්‍රො
-ණ්‍රෝ
-ණ්‍රෞ
-ණ්‍ර්
-ණ්‍රං
-ණ්‍රඃ
-ණ්‍ය
-ණ්‍යා
-ණ්‍යැ
-ණ්‍යෑ
-ණ්‍යි
-ණ්‍යී
-ණ්‍යු
-ණ්‍යූ
-ණ්‍යෘ
-ණ්‍යෲ
-ණ්‍යෟ
-ණ්‍යෳ
-ණ්‍යෙ
-ණ්‍යේ
-ණ්‍යෛ
-ණ්‍යො
-ණ්‍යෝ
-ණ්‍යෞ
-ණ්‍ය්
-ණ්‍යං
-ණ්‍යඃ
-ර්‍ණ
-ර්‍ණා
-ර්‍ණැ
-ර්‍ණෑ
-ර්‍ණි
-ර්‍ණී
-ර්‍ණු
-ර්‍ණූ
-ර්‍ණෘ
-ර්‍ණෲ
-ර්‍ණෟ
-ර්‍ණෳ
-ර්‍ණෙ
-ර්‍ණේ
-ර්‍ණෛ
-ර්‍ණො
-ර්‍ණෝ
-ර්‍ණෞ
-ර්‍ණ්
-ර්‍ණං
-ර්‍ණඃ
-ඬ
-ඬා
-ඬැ
-ඬෑ
-ඬි
-ඬී
-ඬු
-ඬූ
-ඬෘ
-ඬෲ
-ඬෟ
-ඬෳ
-ඬෙ
-ඬේ
-ඬෛ
-ඬො
-ඬෝ
-ඬෞ
-ඬ්
-ඬං
-ඬඃ
-ඬ්‍ර
-ඬ්‍රා
-ඬ්‍රැ
-ඬ්‍රෑ
-ඬ්‍රි
-ඬ්‍රී
-ඬ්‍රු
-ඬ්‍රූ
-ඬ්‍රෘ
-ඬ්‍රෲ
-ඬ්‍රෟ
-ඬ්‍රෳ
-ඬ්‍රෙ
-ඬ්‍රේ
-ඬ්‍රෛ
-ඬ්‍රො
-ඬ්‍රෝ
-ඬ්‍රෞ
-ඬ්‍ර්
-ඬ්‍රං
-ඬ්‍රඃ
-ඬ්‍ය
-ඬ්‍යා
-ඬ්‍යැ
-ඬ්‍යෑ
-ඬ්‍යි
-ඬ්‍යී
-ඬ්‍යු
-ඬ්‍යූ
-ඬ්‍යෘ
-ඬ්‍යෲ
-ඬ්‍යෟ
-ඬ්‍යෳ
-ඬ්‍යෙ
-ඬ්‍යේ
-ඬ්‍යෛ
-ඬ්‍යො
-ඬ්‍යෝ
-ඬ්‍යෞ
-ඬ්‍ය්
-ඬ්‍යං
-ඬ්‍යඃ
-ර්‍ඬ
-ර්‍ඬා
-ර්‍ඬැ
-ර්‍ඬෑ
-ර්‍ඬි
-ර්‍ඬී
-ර්‍ඬු
-ර්‍ඬූ
-ර්‍ඬෘ
-ර්‍ඬෲ
-ර්‍ඬෟ
-ර්‍ඬෳ
-ර්‍ඬෙ
-ර්‍ඬේ
-ර්‍ඬෛ
-ර්‍ඬො
-ර්‍ඬෝ
-ර්‍ඬෞ
-ර්‍ඬ්
-ර්‍ඬං
-ර්‍ඬඃ
-ත
-තා
-තැ
-තෑ
-ති
-තී
-තු
-තූ
-තෘ
-තෲ
-තෟ
-තෳ
-තෙ
-තේ
-තෛ
-තො
-තෝ
-තෞ
-ත්
-තං
-තඃ
-ත්‍ර
-ත්‍රා
-ත්‍රැ
-ත්‍රෑ
-ත්‍රි
-ත්‍රී
-ත්‍රු
-ත්‍රූ
-ත්‍රෘ
-ත්‍රෲ
-ත්‍රෟ
-ත්‍රෳ
-ත්‍රෙ
-ත්‍රේ
-ත්‍රෛ
-ත්‍රො
-ත්‍රෝ
-ත්‍රෞ
-ත්‍ර්
-ත්‍රං
-ත්‍රඃ
-ත්‍ය
-ත්‍යා
-ත්‍යැ
-ත්‍යෑ
-ත්‍යි
-ත්‍යී
-ත්‍යු
-ත්‍යූ
-ත්‍යෘ
-ත්‍යෲ
-ත්‍යෟ
-ත්‍යෳ
-ත්‍යෙ
-ත්‍යේ
-ත්‍යෛ
-ත්‍යො
-ත්‍යෝ
-ත්‍යෞ
-ත්‍ය්
-ත්‍යං
-ත්‍යඃ
-ර්‍ත
-ර්‍තා
-ර්‍තැ
-ර්‍තෑ
-ර්‍ති
-ර්‍තී
-ර්‍තු
-ර්‍තූ
-ර්‍තෘ
-ර්‍තෲ
-ර්‍තෟ
-ර්‍තෳ
-ර්‍තෙ
-ර්‍තේ
-ර්‍තෛ
-ර්‍තො
-ර්‍තෝ
-ර්‍තෞ
-ර්‍ත්
-ර්‍තං
-ර්‍තඃ
-ථ
-ථා
-ථැ
-ථෑ
-ථි
-ථී
-ථු
-ථූ
-ථෘ
-ථෲ
-ථෟ
-ථෳ
-ථෙ
-ථේ
-ථෛ
-ථො
-ථෝ
-ථෞ
-ථ්
-ථං
-ථඃ
-ථ්‍ර
-ථ්‍රා
-ථ්‍රැ
-ථ්‍රෑ
-ථ්‍රි
-ථ්‍රී
-ථ්‍රු
-ථ්‍රූ
-ථ්‍රෘ
-ථ්‍රෲ
-ථ්‍රෟ
-ථ්‍රෳ
-ථ්‍රෙ
-ථ්‍රේ
-ථ්‍රෛ
-ථ්‍රො
-ථ්‍රෝ
-ථ්‍රෞ
-ථ්‍ර්
-ථ්‍රං
-ථ්‍රඃ
-ථ්‍ය
-ථ්‍යා
-ථ්‍යැ
-ථ්‍යෑ
-ථ්‍යි
-ථ්‍යී
-ථ්‍යු
-ථ්‍යූ
-ථ්‍යෘ
-ථ්‍යෲ
-ථ්‍යෟ
-ථ්‍යෳ
-ථ්‍යෙ
-ථ්‍යේ
-ථ්‍යෛ
-ථ්‍යො
-ථ්‍යෝ
-ථ්‍යෞ
-ථ්‍ය්
-ථ්‍යං
-ථ්‍යඃ
-ර්‍ථ
-ර්‍ථා
-ර්‍ථැ
-ර්‍ථෑ
-ර්‍ථි
-ර්‍ථී
-ර්‍ථු
-ර්‍ථූ
-ර්‍ථෘ
-ර්‍ථෲ
-ර්‍ථෟ
-ර්‍ථෳ
-ර්‍ථෙ
-ර්‍ථේ
-ර්‍ථෛ
-ර්‍ථො
-ර්‍ථෝ
-ර්‍ථෞ
-ර්‍ථ්
-ර්‍ථං
-ර්‍ථඃ
-ද
-දා
-දැ
-දෑ
-දි
-දී
-දු
-දූ
-දෘ
-දෲ
-දෟ
-දෳ
-දෙ
-දේ
-දෛ
-දො
-දෝ
-දෞ
-ද්
-දං
-දඃ
-ද්‍ර
-ද්‍රා
-ද්‍රැ
-ද්‍රෑ
-ද්‍රි
-ද්‍රී
-ද්‍රු
-ද්‍රූ
-ද්‍රෘ
-ද්‍රෲ
-ද්‍රෟ
-ද්‍රෳ
-ද්‍රෙ
-ද්‍රේ
-ද්‍රෛ
-ද්‍රො
-ද්‍රෝ
-ද්‍රෞ
-ද්‍ර්
-ද්‍රං
-ද්‍රඃ
-ද්‍ය
-ද්‍යා
-ද්‍යැ
-ද්‍යෑ
-ද්‍යි
-ද්‍යී
-ද්‍යු
-ද්‍යූ
-ද්‍යෘ
-ද්‍යෲ
-ද්‍යෟ
-ද්‍යෳ
-ද්‍යෙ
-ද්‍යේ
-ද්‍යෛ
-ද්‍යො
-ද්‍යෝ
-ද්‍යෞ
-ද්‍ය්
-ද්‍යං
-ද්‍යඃ
-ර්‍ද
-ර්‍දා
-ර්‍දැ
-ර්‍දෑ
-ර්‍දි
-ර්‍දී
-ර්‍දු
-ර්‍දූ
-ර්‍දෘ
-ර්‍දෲ
-ර්‍දෟ
-ර්‍දෳ
-ර්‍දෙ
-ර්‍දේ
-ර්‍දෛ
-ර්‍දො
-ර්‍දෝ
-ර්‍දෞ
-ර්‍ද්
-ර්‍දං
-ර්‍දඃ
-ධ
-ධා
-ධැ
-ධෑ
-ධි
-ධී
-ධු
-ධූ
-ධෘ
-ධෲ
-ධෟ
-ධෳ
-ධෙ
-ධේ
-ධෛ
-ධො
-ධෝ
-ධෞ
-ධ්
-ධං
-ධඃ
-ධ්‍ර
-ධ්‍රා
-ධ්‍රැ
-ධ්‍රෑ
-ධ්‍රි
-ධ්‍රී
-ධ්‍රු
-ධ්‍රූ
-ධ්‍රෘ
-ධ්‍රෲ
-ධ්‍රෟ
-ධ්‍රෳ
-ධ්‍රෙ
-ධ්‍රේ
-ධ්‍රෛ
-ධ්‍රො
-ධ්‍රෝ
-ධ්‍රෞ
-ධ්‍ර්
-ධ්‍රං
-ධ්‍රඃ
-ධ්‍ය
-ධ්‍යා
-ධ්‍යැ
-ධ්‍යෑ
-ධ්‍යි
-ධ්‍යී
-ධ්‍යු
-ධ්‍යූ
-ධ්‍යෘ
-ධ්‍යෲ
-ධ්‍යෟ
-ධ්‍යෳ
-ධ්‍යෙ
-ධ්‍යේ
-ධ්‍යෛ
-ධ්‍යො
-ධ්‍යෝ
-ධ්‍යෞ
-ධ්‍ය්
-ධ්‍යං
-ධ්‍යඃ
-ර්‍ධ
-ර්‍ධා
-ර්‍ධැ
-ර්‍ධෑ
-ර්‍ධි
-ර්‍ධී
-ර්‍ධු
-ර්‍ධූ
-ර්‍ධෘ
-ර්‍ධෲ
-ර්‍ධෟ
-ර්‍ධෳ
-ර්‍ධෙ
-ර්‍ධේ
-ර්‍ධෛ
-ර්‍ධො
-ර්‍ධෝ
-ර්‍ධෞ
-ර්‍ධ්
-ර්‍ධං
-ර්‍ධඃ
-න
-නා
-නැ
-නෑ
-නි
-නී
-නු
-නූ
-නෘ
-නෲ
-නෟ
-නෳ
-නෙ
-නේ
-නෛ
-නො
-නෝ
-නෞ
-න්
-නං
-නඃ
-න්‍ර
-න්‍රා
-න්‍රැ
-න්‍රෑ
-න්‍රි
-න්‍රී
-න්‍රු
-න්‍රූ
-න්‍රෘ
-න්‍රෲ
-න්‍රෟ
-න්‍රෳ
-න්‍රෙ
-න්‍රේ
-න්‍රෛ
-න්‍රො
-න්‍රෝ
-න්‍රෞ
-න්‍ර්
-න්‍රං
-න්‍රඃ
-න්‍ය
-න්‍යා
-න්‍යැ
-න්‍යෑ
-න්‍යි
-න්‍යී
-න්‍යු
-න්‍යූ
-න්‍යෘ
-න්‍යෲ
-න්‍යෟ
-න්‍යෳ
-න්‍යෙ
-න්‍යේ
-න්‍යෛ
-න්‍යො
-න්‍යෝ
-න්‍යෞ
-න්‍ය්
-න්‍යං
-න්‍යඃ
-ර්‍න
-ර්‍නා
-ර්‍නැ
-ර්‍නෑ
-ර්‍නි
-ර්‍නී
-ර්‍නු
-ර්‍නූ
-ර්‍නෘ
-ර්‍නෲ
-ර්‍නෟ
-ර්‍නෳ
-ර්‍නෙ
-ර්‍නේ
-ර්‍නෛ
-ර්‍නො
-ර්‍නෝ
-ර්‍නෞ
-ර්‍න්
-ර්‍නං
-ර්‍නඃ
-ඳ
-ඳා
-ඳැ
-ඳෑ
-ඳි
-ඳී
-ඳු
-ඳූ
-ඳෘ
-ඳෲ
-ඳෟ
-ඳෳ
-ඳෙ
-ඳේ
-ඳෛ
-ඳො
-ඳෝ
-ඳෞ
-ඳ්
-ඳං
-ඳඃ
-ඳ්‍ර
-ඳ්‍රා
-ඳ්‍රැ
-ඳ්‍රෑ
-ඳ්‍රි
-ඳ්‍රී
-ඳ්‍රු
-ඳ්‍රූ
-ඳ්‍රෘ
-ඳ්‍රෲ
-ඳ්‍රෟ
-ඳ්‍රෳ
-ඳ්‍රෙ
-ඳ්‍රේ
-ඳ්‍රෛ
-ඳ්‍රො
-ඳ්‍රෝ
-ඳ්‍රෞ
-ඳ්‍ර්
-ඳ්‍රං
-ඳ්‍රඃ
-ඳ්‍ය
-ඳ්‍යා
-ඳ්‍යැ
-ඳ්‍යෑ
-ඳ්‍යි
-ඳ්‍යී
-ඳ්‍යු
-ඳ්‍යූ
-ඳ්‍යෘ
-ඳ්‍යෲ
-ඳ්‍යෟ
-ඳ්‍යෳ
-ඳ්‍යෙ
-ඳ්‍යේ
-ඳ්‍යෛ
-ඳ්‍යො
-ඳ්‍යෝ
-ඳ්‍යෞ
-ඳ්‍ය්
-ඳ්‍යං
-ඳ්‍යඃ
-ර්‍ඳ
-ර්‍ඳා
-ර්‍ඳැ
-ර්‍ඳෑ
-ර්‍ඳි
-ර්‍ඳී
-ර්‍ඳු
-ර්‍ඳූ
-ර්‍ඳෘ
-ර්‍ඳෲ
-ර්‍ඳෟ
-ර්‍ඳෳ
-ර්‍ඳෙ
-ර්‍ඳේ
-ර්‍ඳෛ
-ර්‍ඳො
-ර්‍ඳෝ
-ර්‍ඳෞ
-ර්‍ඳ්
-ර්‍ඳං
-ර්‍ඳඃ
-ප
-පා
-පැ
-පෑ
-පි
-පී
-පු
-පූ
-පෘ
-පෲ
-පෟ
-පෳ
-පෙ
-පේ
-පෛ
-පො
-පෝ
-පෞ
-ප්
-පං
-පඃ
-ප්‍ර
-ප්‍රා
-ප්‍රැ
-ප්‍රෑ
-ප්‍රි
-ප්‍රී
-ප්‍රු
-ප්‍රූ
-ප්‍රෘ
-ප්‍රෲ
-ප්‍රෟ
-ප්‍රෳ
-ප්‍රෙ
-ප්‍රේ
-ප්‍රෛ
-ප්‍රො
-ප්‍රෝ
-ප්‍රෞ
-ප්‍ර්
-ප්‍රං
-ප්‍රඃ
-ප්‍ය
-ප්‍යා
-ප්‍යැ
-ප්‍යෑ
-ප්‍යි
-ප්‍යී
-ප්‍යු
-ප්‍යූ
-ප්‍යෘ
-ප්‍යෲ
-ප්‍යෟ
-ප්‍යෳ
-ප්‍යෙ
-ප්‍යේ
-ප්‍යෛ
-ප්‍යො
-ප්‍යෝ
-ප්‍යෞ
-ප්‍ය්
-ප්‍යං
-ප්‍යඃ
-ර්‍ප
-ර්‍පා
-ර්‍පැ
-ර්‍පෑ
-ර්‍පි
-ර්‍පී
-ර්‍පු
-ර්‍පූ
-ර්‍පෘ
-ර්‍පෲ
-ර්‍පෟ
-ර්‍පෳ
-ර්‍පෙ
-ර්‍පේ
-ර්‍පෛ
-ර්‍පො
-ර්‍පෝ
-ර්‍පෞ
-ර්‍ප්
-ර්‍පං
-ර්‍පඃ
-ඵ
-ඵා
-ඵැ
-ඵෑ
-ඵි
-ඵී
-ඵු
-ඵූ
-ඵෘ
-ඵෲ
-ඵෟ
-ඵෳ
-ඵෙ
-ඵේ
-ඵෛ
-ඵො
-ඵෝ
-ඵෞ
-ඵ්
-ඵං
-ඵඃ
-ඵ්‍ර
-ඵ්‍රා
-ඵ්‍රැ
-ඵ්‍රෑ
-ඵ්‍රි
-ඵ්‍රී
-ඵ්‍රු
-ඵ්‍රූ
-ඵ්‍රෘ
-ඵ්‍රෲ
-ඵ්‍රෟ
-ඵ්‍රෳ
-ඵ්‍රෙ
-ඵ්‍රේ
-ඵ්‍රෛ
-ඵ්‍රො
-ඵ්‍රෝ
-ඵ්‍රෞ
-ඵ්‍ර්
-ඵ්‍රං
-ඵ්‍රඃ
-ඵ්‍ය
-ඵ්‍යා
-ඵ්‍යැ
-ඵ්‍යෑ
-ඵ්‍යි
-ඵ්‍යී
-ඵ්‍යු
-ඵ්‍යූ
-ඵ්‍යෘ
-ඵ්‍යෲ
-ඵ්‍යෟ
-ඵ්‍යෳ
-ඵ්‍යෙ
-ඵ්‍යේ
-ඵ්‍යෛ
-ඵ්‍යො
-ඵ්‍යෝ
-ඵ්‍යෞ
-ඵ්‍ය්
-ඵ්‍යං
-ඵ්‍යඃ
-ර්‍ඵ
-ර්‍ඵා
-ර්‍ඵැ
-ර්‍ඵෑ
-ර්‍ඵි
-ර්‍ඵී
-ර්‍ඵු
-ර්‍ඵූ
-ර්‍ඵෘ
-ර්‍ඵෲ
-ර්‍ඵෟ
-ර්‍ඵෳ
-ර්‍ඵෙ
-ර්‍ඵේ
-ර්‍ඵෛ
-ර්‍ඵො
-ර්‍ඵෝ
-ර්‍ඵෞ
-ර්‍ඵ්
-ර්‍ඵං
-ර්‍ඵඃ
-බ
-බා
-බැ
-බෑ
-බි
-බී
-බු
-බූ
-බෘ
-බෲ
-බෟ
-බෳ
-බෙ
-බේ
-බෛ
-බො
-බෝ
-බෞ
-බ්
-බං
-බඃ
-බ්‍ර
-බ්‍රා
-බ්‍රැ
-බ්‍රෑ
-බ්‍රි
-බ්‍රී
-බ්‍රු
-බ්‍රූ
-බ්‍රෘ
-බ්‍රෲ
-බ්‍රෟ
-බ්‍රෳ
-බ්‍රෙ
-බ්‍රේ
-බ්‍රෛ
-බ්‍රො
-බ්‍රෝ
-බ්‍රෞ
-බ්‍ර්
-බ්‍රං
-බ්‍රඃ
-බ්‍ය
-බ්‍යා
-බ්‍යැ
-බ්‍යෑ
-බ්‍යි
-බ්‍යී
-බ්‍යු
-බ්‍යූ
-බ්‍යෘ
-බ්‍යෲ
-බ්‍යෟ
-බ්‍යෳ
-බ්‍යෙ
-බ්‍යේ
-බ්‍යෛ
-බ්‍යො
-බ්‍යෝ
-බ්‍යෞ
-බ්‍ය්
-බ්‍යං
-බ්‍යඃ
-ර්‍බ
-ර්‍බා
-ර්‍බැ
-ර්‍බෑ
-ර්‍බි
-ර්‍බී
-ර්‍බු
-ර්‍බූ
-ර්‍බෘ
-ර්‍බෲ
-ර්‍බෟ
-ර්‍බෳ
-ර්‍බෙ
-ර්‍බේ
-ර්‍බෛ
-ර්‍බො
-ර්‍බෝ
-ර්‍බෞ
-ර්‍බ්
-ර්‍බං
-ර්‍බඃ
-භ
-භා
-භැ
-භෑ
-භි
-භී
-භු
-භූ
-භෘ
-භෲ
-භෟ
-භෳ
-භෙ
-භේ
-භෛ
-භො
-භෝ
-භෞ
-භ්
-භං
-භඃ
-භ්‍ර
-භ්‍රා
-භ්‍රැ
-භ්‍රෑ
-භ්‍රි
-භ්‍රී
-භ්‍රු
-භ්‍රූ
-භ්‍රෘ
-භ්‍රෲ
-භ්‍රෟ
-භ්‍රෳ
-භ්‍රෙ
-භ්‍රේ
-භ්‍රෛ
-භ්‍රො
-භ්‍රෝ
-භ්‍රෞ
-භ්‍ර්
-භ්‍රං
-භ්‍රඃ
-භ්‍ය
-භ්‍යා
-භ්‍යැ
-භ්‍යෑ
-භ්‍යි
-භ්‍යී
-භ්‍යු
-භ්‍යූ
-භ්‍යෘ
-භ්‍යෲ
-භ්‍යෟ
-භ්‍යෳ
-භ්‍යෙ
-භ්‍යේ
-භ්‍යෛ
-භ්‍යො
-භ්‍යෝ
-භ්‍යෞ
-භ්‍ය්
-භ්‍යං
-භ්‍යඃ
-ර්‍භ
-ර්‍භා
-ර්‍භැ
-ර්‍භෑ
-ර්‍භි
-ර්‍භී
-ර්‍භු
-ර්‍භූ
-ර්‍භෘ
-ර්‍භෲ
-ර්‍භෟ
-ර්‍භෳ
-ර්‍භෙ
-ර්‍භේ
-ර්‍භෛ
-ර්‍භො
-ර්‍භෝ
-ර්‍භෞ
-ර්‍භ්
-ර්‍භං
-ර්‍භඃ
-ම
-මා
-මැ
-මෑ
-මි
-මී
-මු
-මූ
-මෘ
-මෲ
-මෟ
-මෳ
-මෙ
-මේ
-මෛ
-මො
-මෝ
-මෞ
-ම්
-මං
-මඃ
-ම්‍ර
-ම්‍රා
-ම්‍රැ
-ම්‍රෑ
-ම්‍රි
-ම්‍රී
-ම්‍රු
-ම්‍රූ
-ම්‍රෘ
-ම්‍රෲ
-ම්‍රෟ
-ම්‍රෳ
-ම්‍රෙ
-ම්‍රේ
-ම්‍රෛ
-ම්‍රො
-ම්‍රෝ
-ම්‍රෞ
-ම්‍ර්
-ම්‍රං
-ම්‍රඃ
-ම්‍ය
-ම්‍යා
-ම්‍යැ
-ම්‍යෑ
-ම්‍යි
-ම්‍යී
-ම්‍යු
-ම්‍යූ
-ම්‍යෘ
-ම්‍යෲ
-ම්‍යෟ
-ම්‍යෳ
-ම්‍යෙ
-ම්‍යේ
-ම්‍යෛ
-ම්‍යො
-ම්‍යෝ
-ම්‍යෞ
-ම්‍ය්
-ම්‍යං
-ම්‍යඃ
-ර්‍ම
-ර්‍මා
-ර්‍මැ
-ර්‍මෑ
-ර්‍මි
-ර්‍මී
-ර්‍මු
-ර්‍මූ
-ර්‍මෘ
-ර්‍මෲ
-ර්‍මෟ
-ර්‍මෳ
-ර්‍මෙ
-ර්‍මේ
-ර්‍මෛ
-ර්‍මො
-ර්‍මෝ
-ර්‍මෞ
-ර්‍ම්
-ර්‍මං
-ර්‍මඃ
-ඹ
-ඹා
-ඹැ
-ඹෑ
-ඹි
-ඹී
-ඹු
-ඹූ
-ඹෘ
-ඹෲ
-ඹෟ
-ඹෳ
-ඹෙ
-ඹේ
-ඹෛ
-ඹො
-ඹෝ
-ඹෞ
-ඹ්
-ඹං
-ඹඃ
-ඹ්‍ර
-ඹ්‍රා
-ඹ්‍රැ
-ඹ්‍රෑ
-ඹ්‍රි
-ඹ්‍රී
-ඹ්‍රු
-ඹ්‍රූ
-ඹ්‍රෘ
-ඹ්‍රෲ
-ඹ්‍රෟ
-ඹ්‍රෳ
-ඹ්‍රෙ
-ඹ්‍රේ
-ඹ්‍රෛ
-ඹ්‍රො
-ඹ්‍රෝ
-ඹ්‍රෞ
-ඹ්‍ර්
-ඹ්‍රං
-ඹ්‍රඃ
-ඹ්‍ය
-ඹ්‍යා
-ඹ්‍යැ
-ඹ්‍යෑ
-ඹ්‍යි
-ඹ්‍යී
-ඹ්‍යු
-ඹ්‍යූ
-ඹ්‍යෘ
-ඹ්‍යෲ
-ඹ්‍යෟ
-ඹ්‍යෳ
-ඹ්‍යෙ
-ඹ්‍යේ
-ඹ්‍යෛ
-ඹ්‍යො
-ඹ්‍යෝ
-ඹ්‍යෞ
-ඹ්‍ය්
-ඹ්‍යං
-ඹ්‍යඃ
-ර්‍ඹ
-ර්‍ඹා
-ර්‍ඹැ
-ර්‍ඹෑ
-ර්‍ඹි
-ර්‍ඹී
-ර්‍ඹු
-ර්‍ඹූ
-ර්‍ඹෘ
-ර්‍ඹෲ
-ර්‍ඹෟ
-ර්‍ඹෳ
-ර්‍ඹෙ
-ර්‍ඹේ
-ර්‍ඹෛ
-ර්‍ඹො
-ර්‍ඹෝ
-ර්‍ඹෞ
-ර්‍ඹ්
-ර්‍ඹං
-ර්‍ඹඃ
-ය
-යා
-යැ
-යෑ
-යි
-යී
-යු
-යූ
-යෘ
-යෲ
-යෟ
-යෳ
-යෙ
-යේ
-යෛ
-යො
-යෝ
-යෞ
-ය්
-යං
-යඃ
-ය්‍ර
-ය්‍රා
-ය්‍රැ
-ය්‍රෑ
-ය්‍රි
-ය්‍රී
-ය්‍රු
-ය්‍රූ
-ය්‍රෘ
-ය්‍රෲ
-ය්‍රෟ
-ය්‍රෳ
-ය්‍රෙ
-ය්‍රේ
-ය්‍රෛ
-ය්‍රො
-ය්‍රෝ
-ය්‍රෞ
-ය්‍ර්
-ය්‍රං
-ය්‍රඃ
-ය්‍ය
-ය්‍යා
-ය්‍යැ
-ය්‍යෑ
-ය්‍යි
-ය්‍යී
-ය්‍යු
-ය්‍යූ
-ය්‍යෘ
-ය්‍යෲ
-ය්‍යෟ
-ය්‍යෳ
-ය්‍යෙ
-ය්‍යේ
-ය්‍යෛ
-ය්‍යො
-ය්‍යෝ
-ය්‍යෞ
-ය්‍ය්
-ය්‍යං
-ය්‍යඃ
-ර්‍ය
-ර්‍යා
-ර්‍යැ
-ර්‍යෑ
-ර්‍යි
-ර්‍යී
-ර්‍යු
-ර්‍යූ
-ර්‍යෘ
-ර්‍යෲ
-ර්‍යෟ
-ර්‍යෳ
-ර්‍යෙ
-ර්‍යේ
-ර්‍යෛ
-ර්‍යො
-ර්‍යෝ
-ර්‍යෞ
-ර්‍ය්
-ර්‍යං
-ර්‍යඃ
-ර
-රා
-රැ
-රෑ
-රි
-රී
-රු
-රූ
-රෘ
-රෲ
-රෟ
-රෳ
-රෙ
-රේ
-රෛ
-රො
-රෝ
-රෞ
-ර්
-රං
-රඃ
-ර්‍ර
-ර්‍රා
-ර්‍රැ
-ර්‍රෑ
-ර්‍රි
-ර්‍රී
-ර්‍රු
-ර්‍රූ
-ර්‍රෘ
-ර්‍රෲ
-ර්‍රෟ
-ර්‍රෳ
-ර්‍රෙ
-ර්‍රේ
-ර්‍රෛ
-ර්‍රො
-ර්‍රෝ
-ර්‍රෞ
-ර්‍ර්
-ර්‍රං
-ර්‍රඃ
-ර්‍ය
-ර්‍යා
-ර්‍යැ
-ර්‍යෑ
-ර්‍යි
-ර්‍යී
-ර්‍යු
-ර්‍යූ
-ර්‍යෘ
-ර්‍යෲ
-ර්‍යෟ
-ර්‍යෳ
-ර්‍යෙ
-ර්‍යේ
-ර්‍යෛ
-ර්‍යො
-ර්‍යෝ
-ර්‍යෞ
-ර්‍ය්
-ර්‍යං
-ර්‍යඃ
-ර්‍ර
-ර්‍රා
-ර්‍රැ
-ර්‍රෑ
-ර්‍රි
-ර්‍රී
-ර්‍රු
-ර්‍රූ
-ර්‍රෘ
-ර්‍රෲ
-ර්‍රෟ
-ර්‍රෳ
-ර්‍රෙ
-ර්‍රේ
-ර්‍රෛ
-ර්‍රො
-ර්‍රෝ
-ර්‍රෞ
-ර්‍ර්
-ර්‍රං
-ර්‍රඃ
-ල
-ලා
-ලැ
-ලෑ
-ලි
-ලී
-ලු
-ලූ
-ලෘ
-ලෲ
-ලෟ
-ලෳ
-ලෙ
-ලේ
-ලෛ
-ලො
-ලෝ
-ලෞ
-ල්
-ලං
-ලඃ
-ල්‍ර
-ල්‍රා
-ල්‍රැ
-ල්‍රෑ
-ල්‍රි
-ල්‍රී
-ල්‍රු
-ල්‍රූ
-ල්‍රෘ
-ල්‍රෲ
-ල්‍රෟ
-ල්‍රෳ
-ල්‍රෙ
-ල්‍රේ
-ල්‍රෛ
-ල්‍රො
-ල්‍රෝ
-ල්‍රෞ
-ල්‍ර්
-ල්‍රං
-ල්‍රඃ
-ල්‍ය
-ල්‍යා
-ල්‍යැ
-ල්‍යෑ
-ල්‍යි
-ල්‍යී
-ල්‍යු
-ල්‍යූ
-ල්‍යෘ
-ල්‍යෲ
-ල්‍යෟ
-ල්‍යෳ
-ල්‍යෙ
-ල්‍යේ
-ල්‍යෛ
-ල්‍යො
-ල්‍යෝ
-ල්‍යෞ
-ල්‍ය්
-ල්‍යං
-ල්‍යඃ
-ර්‍ල
-ර්‍ලා
-ර්‍ලැ
-ර්‍ලෑ
-ර්‍ලි
-ර්‍ලී
-ර්‍ලු
-ර්‍ලූ
-ර්‍ලෘ
-ර්‍ලෲ
-ර්‍ලෟ
-ර්‍ලෳ
-ර්‍ලෙ
-ර්‍ලේ
-ර්‍ලෛ
-ර්‍ලො
-ර්‍ලෝ
-ර්‍ලෞ
-ර්‍ල්
-ර්‍ලං
-ර්‍ලඃ
-ව
-වා
-වැ
-වෑ
-වි
-වී
-වු
-වූ
-වෘ
-වෲ
-වෟ
-වෳ
-වෙ
-වේ
-වෛ
-වො
-වෝ
-වෞ
-ව්
-වං
-වඃ
-ව්‍ර
-ව්‍රා
-ව්‍රැ
-ව්‍රෑ
-ව්‍රි
-ව්‍රී
-ව්‍රු
-ව්‍රූ
-ව්‍රෘ
-ව්‍රෲ
-ව්‍රෟ
-ව්‍රෳ
-ව්‍රෙ
-ව්‍රේ
-ව්‍රෛ
-ව්‍රො
-ව්‍රෝ
-ව්‍රෞ
-ව්‍ර්
-ව්‍රං
-ව්‍රඃ
-ව්‍ය
-ව්‍යා
-ව්‍යැ
-ව්‍යෑ
-ව්‍යි
-ව්‍යී
-ව්‍යු
-ව්‍යූ
-ව්‍යෘ
-ව්‍යෲ
-ව්‍යෟ
-ව්‍යෳ
-ව්‍යෙ
-ව්‍යේ
-ව්‍යෛ
-ව්‍යො
-ව්‍යෝ
-ව්‍යෞ
-ව්‍ය්
-ව්‍යං
-ව්‍යඃ
-ර්‍ව
-ර්‍වා
-ර්‍වැ
-ර්‍වෑ
-ර්‍වි
-ර්‍වී
-ර්‍වු
-ර්‍වූ
-ර්‍වෘ
-ර්‍වෲ
-ර්‍වෟ
-ර්‍වෳ
-ර්‍වෙ
-ර්‍වේ
-ර්‍වෛ
-ර්‍වො
-ර්‍වෝ
-ර්‍වෞ
-ර්‍ව්
-ර්‍වං
-ර්‍වඃ
-ශ
-ශා
-ශැ
-ශෑ
-ශි
-ශී
-ශු
-ශූ
-ශෘ
-ශෲ
-ශෟ
-ශෳ
-ශෙ
-ශේ
-ශෛ
-ශො
-ශෝ
-ශෞ
-ශ්
-ශං
-ශඃ
-ශ්‍ර
-ශ්‍රා
-ශ්‍රැ
-ශ්‍රෑ
-ශ්‍රි
-ශ්‍රී
-ශ්‍රු
-ශ්‍රූ
-ශ්‍රෘ
-ශ්‍රෲ
-ශ්‍රෟ
-ශ්‍රෳ
-ශ්‍රෙ
-ශ්‍රේ
-ශ්‍රෛ
-ශ්‍රො
-ශ්‍රෝ
-ශ්‍රෞ
-ශ්‍ර්
-ශ්‍රං
-ශ්‍රඃ
-ශ්‍ය
-ශ්‍යා
-ශ්‍යැ
-ශ්‍යෑ
-ශ්‍යි
-ශ්‍යී
-ශ්‍යු
-ශ්‍යූ
-ශ්‍යෘ
-ශ්‍යෲ
-ශ්‍යෟ
-ශ්‍යෳ
-ශ්‍යෙ
-ශ්‍යේ
-ශ්‍යෛ
-ශ්‍යො
-ශ්‍යෝ
-ශ්‍යෞ
-ශ්‍ය්
-ශ්‍යං
-ශ්‍යඃ
-ර්‍ශ
-ර්‍ශා
-ර්‍ශැ
-ර්‍ශෑ
-ර්‍ශි
-ර්‍ශී
-ර්‍ශු
-ර්‍ශූ
-ර්‍ශෘ
-ර්‍ශෲ
-ර්‍ශෟ
-ර්‍ශෳ
-ර්‍ශෙ
-ර්‍ශේ
-ර්‍ශෛ
-ර්‍ශො
-ර්‍ශෝ
-ර්‍ශෞ
-ර්‍ශ්
-ර්‍ශං
-ර්‍ශඃ
-ෂ
-ෂා
-ෂැ
-ෂෑ
-ෂි
-ෂී
-ෂු
-ෂූ
-ෂෘ
-ෂෲ
-ෂෟ
-ෂෳ
-ෂෙ
-ෂේ
-ෂෛ
-ෂො
-ෂෝ
-ෂෞ
-ෂ්
-ෂං
-ෂඃ
-ෂ්‍ර
-ෂ්‍රා
-ෂ්‍රැ
-ෂ්‍රෑ
-ෂ්‍රි
-ෂ්‍රී
-ෂ්‍රු
-ෂ්‍රූ
-ෂ්‍රෘ
-ෂ්‍රෲ
-ෂ්‍රෟ
-ෂ්‍රෳ
-ෂ්‍රෙ
-ෂ්‍රේ
-ෂ්‍රෛ
-ෂ්‍රො
-ෂ්‍රෝ
-ෂ්‍රෞ
-ෂ්‍ර්
-ෂ්‍රං
-ෂ්‍රඃ
-ෂ්‍ය
-ෂ්‍යා
-ෂ්‍යැ
-ෂ්‍යෑ
-ෂ්‍යි
-ෂ්‍යී
-ෂ්‍යු
-ෂ්‍යූ
-ෂ්‍යෘ
-ෂ්‍යෲ
-ෂ්‍යෟ
-ෂ්‍යෳ
-ෂ්‍යෙ
-ෂ්‍යේ
-ෂ්‍යෛ
-ෂ්‍යො
-ෂ්‍යෝ
-ෂ්‍යෞ
-ෂ්‍ය්
-ෂ්‍යං
-ෂ්‍යඃ
-ර්‍ෂ
-ර්‍ෂා
-ර්‍ෂැ
-ර්‍ෂෑ
-ර්‍ෂි
-ර්‍ෂී
-ර්‍ෂු
-ර්‍ෂූ
-ර්‍ෂෘ
-ර්‍ෂෲ
-ර්‍ෂෟ
-ර්‍ෂෳ
-ර්‍ෂෙ
-ර්‍ෂේ
-ර්‍ෂෛ
-ර්‍ෂො
-ර්‍ෂෝ
-ර්‍ෂෞ
-ර්‍ෂ්
-ර්‍ෂං
-ර්‍ෂඃ
-ස
-සා
-සැ
-සෑ
-සි
-සී
-සු
-සූ
-සෘ
-සෲ
-සෟ
-සෳ
-සෙ
-සේ
-සෛ
-සො
-සෝ
-සෞ
-ස්
-සං
-සඃ
-ස්‍ර
-ස්‍රා
-ස්‍රැ
-ස්‍රෑ
-ස්‍රි
-ස්‍රී
-ස්‍රු
-ස්‍රූ
-ස්‍රෘ
-ස්‍රෲ
-ස්‍රෟ
-ස්‍රෳ
-ස්‍රෙ
-ස්‍රේ
-ස්‍රෛ
-ස්‍රො
-ස්‍රෝ
-ස්‍රෞ
-ස්‍ර්
-ස්‍රං
-ස්‍රඃ
-ස්‍ය
-ස්‍යා
-ස්‍යැ
-ස්‍යෑ
-ස්‍යි
-ස්‍යී
-ස්‍යු
-ස්‍යූ
-ස්‍යෘ
-ස්‍යෲ
-ස්‍යෟ
-ස්‍යෳ
-ස්‍යෙ
-ස්‍යේ
-ස්‍යෛ
-ස්‍යො
-ස්‍යෝ
-ස්‍යෞ
-ස්‍ය්
-ස්‍යං
-ස්‍යඃ
-ර්‍ස
-ර්‍සා
-ර්‍සැ
-ර්‍සෑ
-ර්‍සි
-ර්‍සී
-ර්‍සු
-ර්‍සූ
-ර්‍සෘ
-ර්‍සෲ
-ර්‍සෟ
-ර්‍සෳ
-ර්‍සෙ
-ර්‍සේ
-ර්‍සෛ
-ර්‍සො
-ර්‍සෝ
-ර්‍සෞ
-ර්‍ස්
-ර්‍සං
-ර්‍සඃ
-හ
-හා
-හැ
-හෑ
-හි
-හී
-හු
-හූ
-හෘ
-හෲ
-හෟ
-හෳ
-හෙ
-හේ
-හෛ
-හො
-හෝ
-හෞ
-හ්
-හං
-හඃ
-හ්‍ර
-හ්‍රා
-හ්‍රැ
-හ්‍රෑ
-හ්‍රි
-හ්‍රී
-හ්‍රු
-හ්‍රූ
-හ්‍රෘ
-හ්‍රෲ
-හ්‍රෟ
-හ්‍රෳ
-හ්‍රෙ
-හ්‍රේ
-හ්‍රෛ
-හ්‍රො
-හ්‍රෝ
-හ්‍රෞ
-හ්‍ර්
-හ්‍රං
-හ්‍රඃ
-හ්‍ය
-හ්‍යා
-හ්‍යැ
-හ්‍යෑ
-හ්‍යි
-හ්‍යී
-හ්‍යු
-හ්‍යූ
-හ්‍යෘ
-හ්‍යෲ
-හ්‍යෟ
-හ්‍යෳ
-හ්‍යෙ
-හ්‍යේ
-හ්‍යෛ
-හ්‍යො
-හ්‍යෝ
-හ්‍යෞ
-හ්‍ය්
-හ්‍යං
-හ්‍යඃ
-ර්‍හ
-ර්‍හා
-ර්‍හැ
-ර්‍හෑ
-ර්‍හි
-ර්‍හී
-ර්‍හු
-ර්‍හූ
-ර්‍හෘ
-ර්‍හෲ
-ර්‍හෟ
-ර්‍හෳ
-ර්‍හෙ
-ර්‍හේ
-ර්‍හෛ
-ර්‍හො
-ර්‍හෝ
-ර්‍හෞ
-ර්‍හ්
-ර්‍හං
-ර්‍හඃ
-ළ
-ළා
-ළැ
-ළෑ
-ළි
-ළී
-ළු
-ළූ
-ළෘ
-ළෲ
-ළෟ
-ළෳ
-ළෙ
-ළේ
-ළෛ
-ළො
-ළෝ
-ළෞ
-ළ්
-ළං
-ළඃ
-ළ්‍ර
-ළ්‍රා
-ළ්‍රැ
-ළ්‍රෑ
-ළ්‍රි
-ළ්‍රී
-ළ්‍රු
-ළ්‍රූ
-ළ්‍රෘ
-ළ්‍රෲ
-ළ්‍රෟ
-ළ්‍රෳ
-ළ්‍රෙ
-ළ්‍රේ
-ළ්‍රෛ
-ළ්‍රො
-ළ්‍රෝ
-ළ්‍රෞ
-ළ්‍ර්
-ළ්‍රං
-ළ්‍රඃ
-ළ්‍ය
-ළ්‍යා
-ළ්‍යැ
-ළ්‍යෑ
-ළ්‍යි
-ළ්‍යී
-ළ්‍යු
-ළ්‍යූ
-ළ්‍යෘ
-ළ්‍යෲ
-ළ්‍යෟ
-ළ්‍යෳ
-ළ්‍යෙ
-ළ්‍යේ
-ළ්‍යෛ
-ළ්‍යො
-ළ්‍යෝ
-ළ්‍යෞ
-ළ්‍ය්
-ළ්‍යං
-ළ්‍යඃ
-ර්‍ළ
-ර්‍ළා
-ර්‍ළැ
-ර්‍ළෑ
-ර්‍ළි
-ර්‍ළී
-ර්‍ළු
-ර්‍ළූ
-ර්‍ළෘ
-ර්‍ළෲ
-ර්‍ළෟ
-ර්‍ළෳ
-ර්‍ළෙ
-ර්‍ළේ
-ර්‍ළෛ
-ර්‍ළො
-ර්‍ළෝ
-ර්‍ළෞ
-ර්‍ළ්
-ර්‍ළං
-ර්‍ළඃ
-ෆ
-ෆා
-ෆැ
-ෆෑ
-ෆි
-ෆී
-ෆු
-ෆූ
-ෆෘ
-ෆෲ
-ෆෟ
-ෆෳ
-ෆෙ
-ෆේ
-ෆෛ
-ෆො
-ෆෝ
-ෆෞ
-ෆ්
-ෆං
-ෆඃ
-ෆ්‍ර
-ෆ්‍රා
-ෆ්‍රැ
-ෆ්‍රෑ
-ෆ්‍රි
-ෆ්‍රී
-ෆ්‍රු
-ෆ්‍රූ
-ෆ්‍රෘ
-ෆ්‍රෲ
-ෆ්‍රෟ
-ෆ්‍රෳ
-ෆ්‍රෙ
-ෆ්‍රේ
-ෆ්‍රෛ
-ෆ්‍රො
-ෆ්‍රෝ
-ෆ්‍රෞ
-ෆ්‍ර්
-ෆ්‍රං
-ෆ්‍රඃ
-ෆ්‍ය
-ෆ්‍යා
-ෆ්‍යැ
-ෆ්‍යෑ
-ෆ්‍යි
-ෆ්‍යී
-ෆ්‍යු
-ෆ්‍යූ
-ෆ්‍යෘ
-ෆ්‍යෲ
-ෆ්‍යෟ
-ෆ්‍යෳ
-ෆ්‍යෙ
-ෆ්‍යේ
-ෆ්‍යෛ
-ෆ්‍යො
-ෆ්‍යෝ
-ෆ්‍යෞ
-ෆ්‍ය්
-ෆ්‍යං
-ෆ්‍යඃ
-ර්‍ෆ
-ර්‍ෆා
-ර්‍ෆැ
-ර්‍ෆෑ
-ර්‍ෆි
-ර්‍ෆී
-ර්‍ෆු
-ර්‍ෆූ
-ර්‍ෆෘ
-ර්‍ෆෲ
-ර්‍ෆෟ
-ර්‍ෆෳ
-ර්‍ෆෙ
-ර්‍ෆේ
-ර්‍ෆෛ
-ර්‍ෆො
-ර්‍ෆෝ
-ර්‍ෆෞ
-ර්‍ෆ්
-ර්‍ෆං
-ර්‍ෆඃ
-ක්‍ෂ
-ක්‍ෂා
-ක්‍ෂැ
-ක්‍ෂෑ
-ක්‍ෂි
-ක්‍ෂී
-ක්‍ෂු
-ක්‍ෂූ
-ක්‍ෂෘ
-ක්‍ෂෲ
-ක්‍ෂෟ
-ක්‍ෂෳ
-ක්‍ෂෙ
-ක්‍ෂේ
-ක්‍ෂෛ
-ක්‍ෂො
-ක්‍ෂෝ
-ක්‍ෂෞ
-ක්‍ෂ්
-ක්‍ෂං
-ක්‍ෂඃ
-ක්‍ෂ්‍ර
-ක්‍ෂ්‍රා
-ක්‍ෂ්‍රැ
-ක්‍ෂ්‍රෑ
-ක්‍ෂ්‍රි
-ක්‍ෂ්‍රී
-ක්‍ෂ්‍රු
-ක්‍ෂ්‍රූ
-ක්‍ෂ්‍රෘ
-ක්‍ෂ්‍රෲ
-ක්‍ෂ්‍රෟ
-ක්‍ෂ්‍රෳ
-ක්‍ෂ්‍රෙ
-ක්‍ෂ්‍රේ
-ක්‍ෂ්‍රෛ
-ක්‍ෂ්‍රො
-ක්‍ෂ්‍රෝ
-ක්‍ෂ්‍රෞ
-ක්‍ෂ්‍ර්
-ක්‍ෂ්‍රං
-ක්‍ෂ්‍රඃ
-ක්‍ෂ්‍ය
-ක්‍ෂ්‍යා
-ක්‍ෂ්‍යැ
-ක්‍ෂ්‍යෑ
-ක්‍ෂ්‍යි
-ක්‍ෂ්‍යී
-ක්‍ෂ්‍යු
-ක්‍ෂ්‍යූ
-ක්‍ෂ්‍යෘ
-ක්‍ෂ්‍යෲ
-ක්‍ෂ්‍යෟ
-ක්‍ෂ්‍යෳ
-ක්‍ෂ්‍යෙ
-ක්‍ෂ්‍යේ
-ක්‍ෂ්‍යෛ
-ක්‍ෂ්‍යො
-ක්‍ෂ්‍යෝ
-ක්‍ෂ්‍යෞ
-ක්‍ෂ්‍ය්
-ක්‍ෂ්‍යං
-ක්‍ෂ්‍යඃ
-ර්‍ක්‍ෂ
-ර්‍ක්‍ෂා
-ර්‍ක්‍ෂැ
-ර්‍ක්‍ෂෑ
-ර්‍ක්‍ෂි
-ර්‍ක්‍ෂී
-ර්‍ක්‍ෂු
-ර්‍ක්‍ෂූ
-ර්‍ක්‍ෂෘ
-ර්‍ක්‍ෂෲ
-ර්‍ක්‍ෂෟ
-ර්‍ක්‍ෂෳ
-ර්‍ක්‍ෂෙ
-ර්‍ක්‍ෂේ
-ර්‍ක්‍ෂෛ
-ර්‍ක්‍ෂො
-ර්‍ක්‍ෂෝ
-ර්‍ක්‍ෂෞ
-ර්‍ක්‍ෂ්
-ර්‍ක්‍ෂං
-ර්‍ක්‍ෂඃ
-ක්‍ව
-ක්‍වා
-ක්‍වැ
-ක්‍වෑ
-ක්‍වි
-ක්‍වී
-ක්‍වු
-ක්‍වූ
-ක්‍වෘ
-ක්‍වෲ
-ක්‍වෟ
-ක්‍වෳ
-ක්‍වෙ
-ක්‍වේ
-ක්‍වෛ
-ක්‍වො
-ක්‍වෝ
-ක්‍වෞ
-ක්‍ව්
-ක්‍වං
-ක්‍වඃ
-ක්‍ව්‍ර
-ක්‍ව්‍රා
-ක්‍ව්‍රැ
-ක්‍ව්‍රෑ
-ක්‍ව්‍රි
-ක්‍ව්‍රී
-ක්‍ව්‍රු
-ක්‍ව්‍රූ
-ක්‍ව්‍රෘ
-ක්‍ව්‍රෲ
-ක්‍ව්‍රෟ
-ක්‍ව්‍රෳ
-ක්‍ව්‍රෙ
-ක්‍ව්‍රේ
-ක්‍ව්‍රෛ
-ක්‍ව්‍රො
-ක්‍ව්‍රෝ
-ක්‍ව්‍රෞ
-ක්‍ව්‍ර්
-ක්‍ව්‍රං
-ක්‍ව්‍රඃ
-ක්‍ව්‍ය
-ක්‍ව්‍යා
-ක්‍ව්‍යැ
-ක්‍ව්‍යෑ
-ක්‍ව්‍යි
-ක්‍ව්‍යී
-ක්‍ව්‍යු
-ක්‍ව්‍යූ
-ක්‍ව්‍යෘ
-ක්‍ව්‍යෲ
-ක්‍ව්‍යෟ
-ක්‍ව්‍යෳ
-ක්‍ව්‍යෙ
-ක්‍ව්‍යේ
-ක්‍ව්‍යෛ
-ක්‍ව්‍යො
-ක්‍ව්‍යෝ
-ක්‍ව්‍යෞ
-ක්‍ව්‍ය්
-ක්‍ව්‍යං
-ක්‍ව්‍යඃ
-ර්‍ක්‍ව
-ර්‍ක්‍වා
-ර්‍ක්‍වැ
-ර්‍ක්‍වෑ
-ර්‍ක්‍වි
-ර්‍ක්‍වී
-ර්‍ක්‍වු
-ර්‍ක්‍වූ
-ර්‍ක්‍වෘ
-ර්‍ක්‍වෲ
-ර්‍ක්‍වෟ
-ර්‍ක්‍වෳ
-ර්‍ක්‍වෙ
-ර්‍ක්‍වේ
-ර්‍ක්‍වෛ
-ර්‍ක්‍වො
-ර්‍ක්‍වෝ
-ර්‍ක්‍වෞ
-ර්‍ක්‍ව්
-ර්‍ක්‍වං
-ර්‍ක්‍වඃ
-ත්‍ථ
-ත්‍ථා
-ත්‍ථැ
-ත්‍ථෑ
-ත්‍ථි
-ත්‍ථී
-ත්‍ථු
-ත්‍ථූ
-ත්‍ථෘ
-ත්‍ථෲ
-ත්‍ථෟ
-ත්‍ථෳ
-ත්‍ථෙ
-ත්‍ථේ
-ත්‍ථෛ
-ත්‍ථො
-ත්‍ථෝ
-ත්‍ථෞ
-ත්‍ථ්
-ත්‍ථං
-ත්‍ථඃ
-ත්‍ථ්‍ර
-ත්‍ථ්‍රා
-ත්‍ථ්‍රැ
-ත්‍ථ්‍රෑ
-ත්‍ථ්‍රි
-ත්‍ථ්‍රී
-ත්‍ථ්‍රු
-ත්‍ථ්‍රූ
-ත්‍ථ්‍රෘ
-ත්‍ථ්‍රෲ
-ත්‍ථ්‍රෟ
-ත්‍ථ්‍රෳ
-ත්‍ථ්‍රෙ
-ත්‍ථ්‍රේ
-ත්‍ථ්‍රෛ
-ත්‍ථ්‍රො
-ත්‍ථ්‍රෝ
-ත්‍ථ්‍රෞ
-ත්‍ථ්‍ර්
-ත්‍ථ්‍රං
-ත්‍ථ්‍රඃ
-ත්‍ථ්‍ය
-ත්‍ථ්‍යා
-ත්‍ථ්‍යැ
-ත්‍ථ්‍යෑ
-ත්‍ථ්‍යි
-ත්‍ථ්‍යී
-ත්‍ථ්‍යු
-ත්‍ථ්‍යූ
-ත්‍ථ්‍යෘ
-ත්‍ථ්‍යෲ
-ත්‍ථ්‍යෟ
-ත්‍ථ්‍යෳ
-ත්‍ථ්‍යෙ
-ත්‍ථ්‍යේ
-ත්‍ථ්‍යෛ
-ත්‍ථ්‍යො
-ත්‍ථ්‍යෝ
-ත්‍ථ්‍යෞ
-ත්‍ථ්‍ය්
-ත්‍ථ්‍යං
-ත්‍ථ්‍යඃ
-ර්‍ත්‍ථ
-ර්‍ත්‍ථා
-ර්‍ත්‍ථැ
-ර්‍ත්‍ථෑ
-ර්‍ත්‍ථි
-ර්‍ත්‍ථී
-ර්‍ත්‍ථු
-ර්‍ත්‍ථූ
-ර්‍ත්‍ථෘ
-ර්‍ත්‍ථෲ
-ර්‍ත්‍ථෟ
-ර්‍ත්‍ථෳ
-ර්‍ත්‍ථෙ
-ර්‍ත්‍ථේ
-ර්‍ත්‍ථෛ
-ර්‍ත්‍ථො
-ර්‍ත්‍ථෝ
-ර්‍ත්‍ථෞ
-ර්‍ත්‍ථ්
-ර්‍ත්‍ථං
-ර්‍ත්‍ථඃ
-ත්‍ව
-ත්‍වා
-ත්‍වැ
-ත්‍වෑ
-ත්‍වි
-ත්‍වී
-ත්‍වු
-ත්‍වූ
-ත්‍වෘ
-ත්‍වෲ
-ත්‍වෟ
-ත්‍වෳ
-ත්‍වෙ
-ත්‍වේ
-ත්‍වෛ
-ත්‍වො
-ත්‍වෝ
-ත්‍වෞ
-ත්‍ව්
-ත්‍වං
-ත්‍වඃ
-ත්‍ව්‍ර
-ත්‍ව්‍රා
-ත්‍ව්‍රැ
-ත්‍ව්‍රෑ
-ත්‍ව්‍රි
-ත්‍ව්‍රී
-ත්‍ව්‍රු
-ත්‍ව්‍රූ
-ත්‍ව්‍රෘ
-ත්‍ව්‍රෲ
-ත්‍ව්‍රෟ
-ත්‍ව්‍රෳ
-ත්‍ව්‍රෙ
-ත්‍ව්‍රේ
-ත්‍ව්‍රෛ
-ත්‍ව්‍රො
-ත්‍ව්‍රෝ
-ත්‍ව්‍රෞ
-ත්‍ව්‍ර්
-ත්‍ව්‍රං
-ත්‍ව්‍රඃ
-ත්‍ව්‍ය
-ත්‍ව්‍යා
-ත්‍ව්‍යැ
-ත්‍ව්‍යෑ
-ත්‍ව්‍යි
-ත්‍ව්‍යී
-ත්‍ව්‍යු
-ත්‍ව්‍යූ
-ත්‍ව්‍යෘ
-ත්‍ව්‍යෲ
-ත්‍ව්‍යෟ
-ත්‍ව්‍යෳ
-ත්‍ව්‍යෙ
-ත්‍ව්‍යේ
-ත්‍ව්‍යෛ
-ත්‍ව්‍යො
-ත්‍ව්‍යෝ
-ත්‍ව්‍යෞ
-ත්‍ව්‍ය්
-ත්‍ව්‍යං
-ත්‍ව්‍යඃ
-ර්‍ත්‍ව
-ර්‍ත්‍වා
-ර්‍ත්‍වැ
-ර්‍ත්‍වෑ
-ර්‍ත්‍වි
-ර්‍ත්‍වී
-ර්‍ත්‍වු
-ර්‍ත්‍වූ
-ර්‍ත්‍වෘ
-ර්‍ත්‍වෲ
-ර්‍ත්‍වෟ
-ර්‍ත්‍වෳ
-ර්‍ත්‍වෙ
-ර්‍ත්‍වේ
-ර්‍ත්‍වෛ
-ර්‍ත්‍වො
-ර්‍ත්‍වෝ
-ර්‍ත්‍වෞ
-ර්‍ත්‍ව්
-ර්‍ත්‍වං
-ර්‍ත්‍වඃ
-න්‍ථ
-න්‍ථා
-න්‍ථැ
-න්‍ථෑ
-න්‍ථි
-න්‍ථී
-න්‍ථු
-න්‍ථූ
-න්‍ථෘ
-න්‍ථෲ
-න්‍ථෟ
-න්‍ථෳ
-න්‍ථෙ
-න්‍ථේ
-න්‍ථෛ
-න්‍ථො
-න්‍ථෝ
-න්‍ථෞ
-න්‍ථ්
-න්‍ථං
-න්‍ථඃ
-න්‍ථ්‍ර
-න්‍ථ්‍රා
-න්‍ථ්‍රැ
-න්‍ථ්‍රෑ
-න්‍ථ්‍රි
-න්‍ථ්‍රී
-න්‍ථ්‍රු
-න්‍ථ්‍රූ
-න්‍ථ්‍රෘ
-න්‍ථ්‍රෲ
-න්‍ථ්‍රෟ
-න්‍ථ්‍රෳ
-න්‍ථ්‍රෙ
-න්‍ථ්‍රේ
-න්‍ථ්‍රෛ
-න්‍ථ්‍රො
-න්‍ථ්‍රෝ
-න්‍ථ්‍රෞ
-න්‍ථ්‍ර්
-න්‍ථ්‍රං
-න්‍ථ්‍රඃ
-න්‍ථ්‍ය
-න්‍ථ්‍යා
-න්‍ථ්‍යැ
-න්‍ථ්‍යෑ
-න්‍ථ්‍යි
-න්‍ථ්‍යී
-න්‍ථ්‍යු
-න්‍ථ්‍යූ
-න්‍ථ්‍යෘ
-න්‍ථ්‍යෲ
-න්‍ථ්‍යෟ
-න්‍ථ්‍යෳ
-න්‍ථ්‍යෙ
-න්‍ථ්‍යේ
-න්‍ථ්‍යෛ
-න්‍ථ්‍යො
-න්‍ථ්‍යෝ
-න්‍ථ්‍යෞ
-න්‍ථ්‍ය්
-න්‍ථ්‍යං
-න්‍ථ්‍යඃ
-ර්‍න්‍ථ
-ර්‍න්‍ථා
-ර්‍න්‍ථැ
-ර්‍න්‍ථෑ
-ර්‍න්‍ථි
-ර්‍න්‍ථී
-ර්‍න්‍ථු
-ර්‍න්‍ථූ
-ර්‍න්‍ථෘ
-ර්‍න්‍ථෲ
-ර්‍න්‍ථෟ
-ර්‍න්‍ථෳ
-ර්‍න්‍ථෙ
-ර්‍න්‍ථේ
-ර්‍න්‍ථෛ
-ර්‍න්‍ථො
-ර්‍න්‍ථෝ
-ර්‍න්‍ථෞ
-ර්‍න්‍ථ්
-ර්‍න්‍ථං
-ර්‍න්‍ථඃ
-න්‍ද
-න්‍දා
-න්‍දැ
-න්‍දෑ
-න්‍දි
-න්‍දී
-න්‍දු
-න්‍දූ
-න්‍දෘ
-න්‍දෲ
-න්‍දෟ
-න්‍දෳ
-න්‍දෙ
-න්‍දේ
-න්‍දෛ
-න්‍දො
-න්‍දෝ
-න්‍දෞ
-න්‍ද්
-න්‍දං
-න්‍දඃ
-න්‍ද්‍ර
-න්‍ද්‍රා
-න්‍ද්‍රැ
-න්‍ද්‍රෑ
-න්‍ද්‍රි
-න්‍ද්‍රී
-න්‍ද්‍රු
-න්‍ද්‍රූ
-න්‍ද්‍රෘ
-න්‍ද්‍රෲ
-න්‍ද්‍රෟ
-න්‍ද්‍රෳ
-න්‍ද්‍රෙ
-න්‍ද්‍රේ
-න්‍ද්‍රෛ
-න්‍ද්‍රො
-න්‍ද්‍රෝ
-න්‍ද්‍රෞ
-න්‍ද්‍ර්
-න්‍ද්‍රං
-න්‍ද්‍රඃ
-න්‍ද්‍ය
-න්‍ද්‍යා
-න්‍ද්‍යැ
-න්‍ද්‍යෑ
-න්‍ද්‍යි
-න්‍ද්‍යී
-න්‍ද්‍යු
-න්‍ද්‍යූ
-න්‍ද්‍යෘ
-න්‍ද්‍යෲ
-න්‍ද්‍යෟ
-න්‍ද්‍යෳ
-න්‍ද්‍යෙ
-න්‍ද්‍යේ
-න්‍ද්‍යෛ
-න්‍ද්‍යො
-න්‍ද්‍යෝ
-න්‍ද්‍යෞ
-න්‍ද්‍ය්
-න්‍ද්‍යං
-න්‍ද්‍යඃ
-ර්‍න්‍ද
-ර්‍න්‍දා
-ර්‍න්‍දැ
-ර්‍න්‍දෑ
-ර්‍න්‍දි
-ර්‍න්‍දී
-ර්‍න්‍දු
-ර්‍න්‍දූ
-ර්‍න්‍දෘ
-ර්‍න්‍දෲ
-ර්‍න්‍දෟ
-ර්‍න්‍දෳ
-ර්‍න්‍දෙ
-ර්‍න්‍දේ
-ර්‍න්‍දෛ
-ර්‍න්‍දො
-ර්‍න්‍දෝ
-ර්‍න්‍දෞ
-ර්‍න්‍ද්
-ර්‍න්‍දං
-ර්‍න්‍දඃ
-න්‍ධ
-න්‍ධා
-න්‍ධැ
-න්‍ධෑ
-න්‍ධි
-න්‍ධී
-න්‍ධු
-න්‍ධූ
-න්‍ධෘ
-න්‍ධෲ
-න්‍ධෟ
-න්‍ධෳ
-න්‍ධෙ
-න්‍ධේ
-න්‍ධෛ
-න්‍ධො
-න්‍ධෝ
-න්‍ධෞ
-න්‍ධ්
-න්‍ධං
-න්‍ධඃ
-න්‍ධ්‍ර
-න්‍ධ්‍රා
-න්‍ධ්‍රැ
-න්‍ධ්‍රෑ
-න්‍ධ්‍රි
-න්‍ධ්‍රී
-න්‍ධ්‍රු
-න්‍ධ්‍රූ
-න්‍ධ්‍රෘ
-න්‍ධ්‍රෲ
-න්‍ධ්‍රෟ
-න්‍ධ්‍රෳ
-න්‍ධ්‍රෙ
-න්‍ධ්‍රේ
-න්‍ධ්‍රෛ
-න්‍ධ්‍රො
-න්‍ධ්‍රෝ
-න්‍ධ්‍රෞ
-න්‍ධ්‍ර්
-න්‍ධ්‍රං
-න්‍ධ්‍රඃ
-න්‍ධ්‍ය
-න්‍ධ්‍යා
-න්‍ධ්‍යැ
-න්‍ධ්‍යෑ
-න්‍ධ්‍යි
-න්‍ධ්‍යී
-න්‍ධ්‍යු
-න්‍ධ්‍යූ
-න්‍ධ්‍යෘ
-න්‍ධ්‍යෲ
-න්‍ධ්‍යෟ
-න්‍ධ්‍යෳ
-න්‍ධ්‍යෙ
-න්‍ධ්‍යේ
-න්‍ධ්‍යෛ
-න්‍ධ්‍යො
-න්‍ධ්‍යෝ
-න්‍ධ්‍යෞ
-න්‍ධ්‍ය්
-න්‍ධ්‍යං
-න්‍ධ්‍යඃ
-ර්‍න්‍ධ
-ර්‍න්‍ධා
-ර්‍න්‍ධැ
-ර්‍න්‍ධෑ
-ර්‍න්‍ධි
-ර්‍න්‍ධී
-ර්‍න්‍ධු
-ර්‍න්‍ධූ
-ර්‍න්‍ධෘ
-ර්‍න්‍ධෲ
-ර්‍න්‍ධෟ
-ර්‍න්‍ධෳ
-ර්‍න්‍ධෙ
-ර්‍න්‍ධේ
-ර්‍න්‍ධෛ
-ර්‍න්‍ධො
-ර්‍න්‍ධෝ
-ර්‍න්‍ධෞ
-ර්‍න්‍ධ්
-ර්‍න්‍ධං
-ර්‍න්‍ධඃ
-න්‍ව
-න්‍වා
-න්‍වැ
-න්‍වෑ
-න්‍වි
-න්‍වී
-න්‍වු
-න්‍වූ
-න්‍වෘ
-න්‍වෲ
-න්‍වෟ
-න්‍වෳ
-න්‍වෙ
-න්‍වේ
-න්‍වෛ
-න්‍වො
-න්‍වෝ
-න්‍වෞ
-න්‍ව්
-න්‍වං
-න්‍වඃ
-න්‍ව්‍ර
-න්‍ව්‍රා
-න්‍ව්‍රැ
-න්‍ව්‍රෑ
-න්‍ව්‍රි
-න්‍ව්‍රී
-න්‍ව්‍රු
-න්‍ව්‍රූ
-න්‍ව්‍රෘ
-න්‍ව්‍රෲ
-න්‍ව්‍රෟ
-න්‍ව්‍රෳ
-න්‍ව්‍රෙ
-න්‍ව්‍රේ
-න්‍ව්‍රෛ
-න්‍ව්‍රො
-න්‍ව්‍රෝ
-න්‍ව්‍රෞ
-න්‍ව්‍ර්
-න්‍ව්‍රං
-න්‍ව්‍රඃ
-න්‍ව්‍ය
-න්‍ව්‍යා
-න්‍ව්‍යැ
-න්‍ව්‍යෑ
-න්‍ව්‍යි
-න්‍ව්‍යී
-න්‍ව්‍යු
-න්‍ව්‍යූ
-න්‍ව්‍යෘ
-න්‍ව්‍යෲ
-න්‍ව්‍යෟ
-න්‍ව්‍යෳ
-න්‍ව්‍යෙ
-න්‍ව්‍යේ
-න්‍ව්‍යෛ
-න්‍ව්‍යො
-න්‍ව්‍යෝ
-න්‍ව්‍යෞ
-න්‍ව්‍ය්
-න්‍ව්‍යං
-න්‍ව්‍යඃ
-ර්‍න්‍ව
-ර්‍න්‍වා
-ර්‍න්‍වැ
-ර්‍න්‍වෑ
-ර්‍න්‍වි
-ර්‍න්‍වී
-ර්‍න්‍වු
-ර්‍න්‍වූ
-ර්‍න්‍වෘ
-ර්‍න්‍වෲ
-ර්‍න්‍වෟ
-ර්‍න්‍වෳ
-ර්‍න්‍වෙ
-ර්‍න්‍වේ
-ර්‍න්‍වෛ
-ර්‍න්‍වො
-ර්‍න්‍වෝ
-ර්‍න්‍වෞ
-ර්‍න්‍ව්
-ර්‍න්‍වං
-ර්‍න්‍වඃ
-ද්‍ව
-ද්‍වා
-ද්‍වැ
-ද්‍වෑ
-ද්‍වි
-ද්‍වී
-ද්‍වු
-ද්‍වූ
-ද්‍වෘ
-ද්‍වෲ
-ද්‍වෟ
-ද්‍වෳ
-ද්‍වෙ
-ද්‍වේ
-ද්‍වෛ
-ද්‍වො
-ද්‍වෝ
-ද්‍වෞ
-ද්‍ව්
-ද්‍වං
-ද්‍වඃ
-ද්‍ව්‍ර
-ද්‍ව්‍රා
-ද්‍ව්‍රැ
-ද්‍ව්‍රෑ
-ද්‍ව්‍රි
-ද්‍ව්‍රී
-ද්‍ව්‍රු
-ද්‍ව්‍රූ
-ද්‍ව්‍රෘ
-ද්‍ව්‍රෲ
-ද්‍ව්‍රෟ
-ද්‍ව්‍රෳ
-ද්‍ව්‍රෙ
-ද්‍ව්‍රේ
-ද්‍ව්‍රෛ
-ද්‍ව්‍රො
-ද්‍ව්‍රෝ
-ද්‍ව්‍රෞ
-ද්‍ව්‍ර්
-ද්‍ව්‍රං
-ද්‍ව්‍රඃ
-ද්‍ව්‍ය
-ද්‍ව්‍යා
-ද්‍ව්‍යැ
-ද්‍ව්‍යෑ
-ද්‍ව්‍යි
-ද්‍ව්‍යී
-ද්‍ව්‍යු
-ද්‍ව්‍යූ
-ද්‍ව්‍යෘ
-ද්‍ව්‍යෲ
-ද්‍ව්‍යෟ
-ද්‍ව්‍යෳ
-ද්‍ව්‍යෙ
-ද්‍ව්‍යේ
-ද්‍ව්‍යෛ
-ද්‍ව්‍යො
-ද්‍ව්‍යෝ
-ද්‍ව්‍යෞ
-ද්‍ව්‍ය්
-ද්‍ව්‍යං
-ද්‍ව්‍යඃ
-ර්‍ද්‍ව
-ර්‍ද්‍වා
-ර්‍ද්‍වැ
-ර්‍ද්‍වෑ
-ර්‍ද්‍වි
-ර්‍ද්‍වී
-ර්‍ද්‍වු
-ර්‍ද්‍වූ
-ර්‍ද්‍වෘ
-ර්‍ද්‍වෲ
-ර්‍ද්‍වෟ
-ර්‍ද්‍වෳ
-ර්‍ද්‍වෙ
-ර්‍ද්‍වේ
-ර්‍ද්‍වෛ
-ර්‍ද්‍වො
-ර්‍ද්‍වෝ
-ර්‍ද්‍වෞ
-ර්‍ද්‍ව්
-ර්‍ද්‍වං
-ර්‍ද්‍වඃ
-ද්‍ධ
-ද්‍ධා
-ද්‍ධැ
-ද්‍ධෑ
-ද්‍ධි
-ද්‍ධී
-ද්‍ධු
-ද්‍ධූ
-ද්‍ධෘ
-ද්‍ධෲ
-ද්‍ධෟ
-ද්‍ධෳ
-ද්‍ධෙ
-ද්‍ධේ
-ද්‍ධෛ
-ද්‍ධො
-ද්‍ධෝ
-ද්‍ධෞ
-ද්‍ධ්
-ද්‍ධං
-ද්‍ධඃ
-ද්‍ධ්‍ර
-ද්‍ධ්‍රා
-ද්‍ධ්‍රැ
-ද්‍ධ්‍රෑ
-ද්‍ධ්‍රි
-ද්‍ධ්‍රී
-ද්‍ධ්‍රු
-ද්‍ධ්‍රූ
-ද්‍ධ්‍රෘ
-ද්‍ධ්‍රෲ
-ද්‍ධ්‍රෟ
-ද්‍ධ්‍රෳ
-ද්‍ධ්‍රෙ
-ද්‍ධ්‍රේ
-ද්‍ධ්‍රෛ
-ද්‍ධ්‍රො
-ද්‍ධ්‍රෝ
-ද්‍ධ්‍රෞ
-ද්‍ධ්‍ර්
-ද්‍ධ්‍රං
-ද්‍ධ්‍රඃ
-ද්‍ධ්‍ය
-ද්‍ධ්‍යා
-ද්‍ධ්‍යැ
-ද්‍ධ්‍යෑ
-ද්‍ධ්‍යි
-ද්‍ධ්‍යී
-ද්‍ධ්‍යු
-ද්‍ධ්‍යූ
-ද්‍ධ්‍යෘ
-ද්‍ධ්‍යෲ
-ද්‍ධ්‍යෟ
-ද්‍ධ්‍යෳ
-ද්‍ධ්‍යෙ
-ද්‍ධ්‍යේ
-ද්‍ධ්‍යෛ
-ද්‍ධ්‍යො
-ද්‍ධ්‍යෝ
-ද්‍ධ්‍යෞ
-ද්‍ධ්‍ය්
-ද්‍ධ්‍යං
-ද්‍ධ්‍යඃ
-ර්‍ද්‍ධ
-ර්‍ද්‍ධා
-ර්‍ද්‍ධැ
-ර්‍ද්‍ධෑ
-ර්‍ද්‍ධි
-ර්‍ද්‍ධී
-ර්‍ද්‍ධු
-ර්‍ද්‍ධූ
-ර්‍ද්‍ධෘ
-ර්‍ද්‍ධෲ
-ර්‍ද්‍ධෟ
-ර්‍ද්‍ධෳ
-ර්‍ද්‍ධෙ
-ර්‍ද්‍ධේ
-ර්‍ද්‍ධෛ
-ර්‍ද්‍ධො
-ර්‍ද්‍ධෝ
-ර්‍ද්‍ධෞ
-ර්‍ද්‍ධ්
-ර්‍ද්‍ධං
-ර්‍ද්‍ධඃ
-ට්‍ඨ
-ට්‍ඨා
-ට්‍ඨැ
-ට්‍ඨෑ
-ට්‍ඨි
-ට්‍ඨී
-ට්‍ඨු
-ට්‍ඨූ
-ට්‍ඨෘ
-ට්‍ඨෲ
-ට්‍ඨෟ
-ට්‍ඨෳ
-ට්‍ඨෙ
-ට්‍ඨේ
-ට්‍ඨෛ
-ට්‍ඨො
-ට්‍ඨෝ
-ට්‍ඨෞ
-ට්‍ඨ්
-ට්‍ඨං
-ට්‍ඨඃ
-ට්‍ඨ්‍ර
-ට්‍ඨ්‍රා
-ට්‍ඨ්‍රැ
-ට්‍ඨ්‍රෑ
-ට්‍ඨ්‍රි
-ට්‍ඨ්‍රී
-ට්‍ඨ්‍රු
-ට්‍ඨ්‍රූ
-ට්‍ඨ්‍රෘ
-ට්‍ඨ්‍රෲ
-ට්‍ඨ්‍රෟ
-ට්‍ඨ්‍රෳ
-ට්‍ඨ්‍රෙ
-ට්‍ඨ්‍රේ
-ට්‍ඨ්‍රෛ
-ට්‍ඨ්‍රො
-ට්‍ඨ්‍රෝ
-ට්‍ඨ්‍රෞ
-ට්‍ඨ්‍ර්
-ට්‍ඨ්‍රං
-ට්‍ඨ්‍රඃ
-ට්‍ඨ්‍ය
-ට්‍ඨ්‍යා
-ට්‍ඨ්‍යැ
-ට්‍ඨ්‍යෑ
-ට්‍ඨ්‍යි
-ට්‍ඨ්‍යී
-ට්‍ඨ්‍යු
-ට්‍ඨ්‍යූ
-ට්‍ඨ්‍යෘ
-ට්‍ඨ්‍යෲ
-ට්‍ඨ්‍යෟ
-ට්‍ඨ්‍යෳ
-ට්‍ඨ්‍යෙ
-ට්‍ඨ්‍යේ
-ට්‍ඨ්‍යෛ
-ට්‍ඨ්‍යො
-ට්‍ඨ්‍යෝ
-ට්‍ඨ්‍යෞ
-ට්‍ඨ්‍ය්
-ට්‍ඨ්‍යං
-ට්‍ඨ්‍යඃ
-ර්‍ට්‍ඨ
-ර්‍ට්‍ඨා
-ර්‍ට්‍ඨැ
-ර්‍ට්‍ඨෑ
-ර්‍ට්‍ඨි
-ර්‍ට්‍ඨී
-ර්‍ට්‍ඨු
-ර්‍ට්‍ඨූ
-ර්‍ට්‍ඨෘ
-ර්‍ට්‍ඨෲ
-ර්‍ට්‍ඨෟ
-ර්‍ට්‍ඨෳ
-ර්‍ට්‍ඨෙ
-ර්‍ට්‍ඨේ
-ර්‍ට්‍ඨෛ
-ර්‍ට්‍ඨො
-ර්‍ට්‍ඨෝ
-ර්‍ට්‍ඨෞ
-ර්‍ට්‍ඨ්
-ර්‍ට්‍ඨං
-ර්‍ට්‍ඨඃ
-්‍ර
-්‍ය
-ර්‍
-෴
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
deleted file mode 100644
index c43cb95b1..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-ක
-කං
-කඃ
-කා
-කැ
-කෑ
-කි
-කී
-කු
-කූ
-කෘ
-කෲ
-කෟ
-කෳ
-කෙ
-කො
-කෞ
-කේ
-කේ
-කෛ
-කො
-කෝ
-කෝ
-කෞ
-ක්
-ක්‍ය
-ක්‍ර
-ක‍්‍රම
-ර්‍ම
-ශී‍්‍ර
-ස්ට්‍රේ
-ග්‍යෙ
-ර්‍ය්‍ය
-එ‍ඬේ
-න්ගේ
-න්‍ගේ
-න‍්ගේ
-ර්‍
-ක්‍රා
-කේ
-ගර්‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
deleted file mode 100644
index f5f2f531f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ර්ධ
-ර්‍ධ
-ර්‌ධ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt
deleted file mode 100644
index 2a73a403a..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-කේ
-කො
-කෝ
-කෞ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 0e8810a29..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-ක
-ඛ
-ග
-ඝ
-ඞ
-ඟ
-ච
-ඡ
-ජ
-ඣ
-ඤ
-ඥ
-ඦ
-ට
-ඨ
-ඩ
-ඪ
-ණ
-ඬ
-ත
-ථ
-ද
-ධ
-න
-ඳ
-ප
-ඵ
-බ
-භ
-ම
-ඹ
-ය
-ර
-ල
-ව
-ශ
-ෂ
-ස
-හ
-ළ
-ෆ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index 27911e4f0..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-ා
-ැ
-ෑ
-ි
-ී
-ු
-ූ
-ෘ
-ෙ
-ේ
-ෛ
-ො
-ෝ
-ෞ
-ෟ
-ෲ
-ෳ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 939be042f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-අ
-ආ
-ඇ
-ඈ
-ඉ
-ඊ
-උ
-ඌ
-ඍ
-ඎ
-ඏ
-ඐ
-එ
-ඒ
-ඓ
-ඔ
-ඕ
-ඖ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
deleted file mode 100644
index d6c680995..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
+++ /dev/null
@@ -1 +0,0 @@
-෴
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index a65a9ba42..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ං
-ඃ
-්
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
deleted file mode 100644
index 7cd1eacfc..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
+++ /dev/null
@@ -1,162 +0,0 @@
-කේ
-කෛ
-කී
-කෑ
-කූ
-කෲ
-ගේ
-ගෛ
-ගී
-ගෑ
-ගූ
-ගෲ
-තේ
-තෛ
-තී
-තෑ
-තූ
-තෲ
-ටේ
-ටෛ
-ටී
-ටෑ
-ටූ
-ටෲ
-ඩේ
-ඩෛ
-ඩී
-ඩෑ
-ඩූ
-ඩෲ
-චේ
-චෛ
-චී
-චෑ
-චූ
-චෲ
-ඡේ
-ඡෛ
-ඡී
-ඡෑ
-ඡූ
-ඡෲ
-ණේ
-ණෛ
-ණී
-ණෑ
-ණූ
-ණෲ
-පේ
-පෛ
-පී
-පෑ
-පූ
-පෲ
-දේ
-දෛ
-දී
-දෑ
-දූ
-දෲ
-ඳේ
-ඳෛ
-ඳී
-ඳෑ
-ඳූ
-ඳෲ
-ධේ
-ධෛ
-ධී
-ධෑ
-ධූ
-ධෲ
-බේ
-බෛ
-බී
-බෑ
-බූ
-බෲ
-මේ
-මෛ
-මී
-මෑ
-මූ
-මෲ
-වේ
-වෛ
-වී
-වෑ
-වූ
-වෲ
-හේ
-හෛ
-හී
-හෑ
-හූ
-හෲ
-රේ
-රෛ
-රී
-රෑ
-රූ
-රෲ
-ෆේ
-ෆෛ
-ෆී
-ෆෑ
-ෆූ
-ෆෲ
-ළේ
-ළෛ
-ළී
-ළෑ
-ළූ
-ළෲ
-ලේ
-ලෛ
-ලී
-ලෑ
-ලූ
-ලෲ
-යේ
-යෛ
-යී
-යෑ
-යූ
-යෲ
-සේ
-සෛ
-සී
-සෑ
-සූ
-සෲ
-ශේ
-ශෛ
-ශී
-ශෑ
-ශූ
-ශෲ
-ෂේ
-ෂෛ
-ෂී
-ෂෑ
-ෂූ
-ෂෲ
-ඹේ
-ඹෛ
-ඹී
-ඹෑ
-ඹූ
-ඹෲ
-ඵේ
-ඵෛ
-ඵී
-ඵෑ
-ඵූ
-ඵෲ
-ථේ
-ථෛ
-ථී
-ථෑ
-ථූ
-ථෲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
deleted file mode 100644
index a100c69e3..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
+++ /dev/null
@@ -1 +0,0 @@
-්‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
deleted file mode 100644
index bf89a7133..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-ක්‍ර
-ඛ්‍ර
-ග්‍ර
-ඝ්‍ර
-ඞ්‍ර
-ඟ්‍ර
-ච්‍ර
-ඡ්‍ර
-ජ්‍ර
-ඣ්‍ර
-ඤ්‍ර
-ඥ්‍ර
-ඦ්‍ර
-ට්‍ර
-ඨ්‍ර
-ඩ්‍ර
-ඪ්‍ර
-ණ්‍ර
-ඬ්‍ර
-ත්‍ර
-ථ්‍ර
-ද්‍ර
-ධ්‍ර
-න්‍ර
-ඳ්‍ර
-ප්‍ර
-ඵ්‍ර
-බ්‍ර
-භ්‍ර
-ම්‍ර
-ඹ්‍ර
-ය්‍ර
-ර්‍ර
-ල්‍ර
-ව්‍ර
-ශ්‍ර
-ෂ්‍ර
-ස්‍ර
-හ්‍ර
-ළ්‍ර
-ෆ්‍ර
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
deleted file mode 100644
index 6f0293d79..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-කර්‍ක
-ඛර්‍ක
-ගර්‍ක
-ඝර්‍ක
-ඞර්‍ක
-ඟර්‍ක
-චර්‍ක
-ඡර්‍ක
-ජර්‍ක
-ඣර්‍ක
-ඤර්‍ක
-ඥර්‍ක
-ඦර්‍ක
-ටර්‍ක
-ඨර්‍ක
-ඩර්‍ක
-ඪර්‍ක
-ණර්‍ක
-ඬර්‍ක
-තර්‍ක
-ථර්‍ක
-දර්‍ක
-ධර්‍ක
-නර්‍ක
-ඳර්‍ක
-පර්‍ක
-ඵර්‍ක
-බර්‍ක
-භර්‍ක
-මර්‍ක
-ඹර්‍ක
-යර්‍ක
-රර්‍ක
-ලර්‍ක
-වර්‍ක
-ශර්‍ක
-ෂර්‍ක
-සර්‍ක
-හර්‍ක
-ළර්‍ක
-ෆර්‍ක
-කර්‍ය්‍ය
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
deleted file mode 100644
index 109c873bb..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ක්‍ෂ
-න්‍ද
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
deleted file mode 100644
index 105b2955e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
+++ /dev/null
@@ -1 +0,0 @@
-‍්
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
deleted file mode 100644
index 299ca9da1..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-ක්‍ය
-ඛ්‍ය
-ග්‍ය
-ඝ්‍ය
-ඞ්‍ය
-ඟ්‍ය
-ච්‍ය
-ඡ්‍ය
-ජ්‍ය
-ඣ්‍ය
-ඤ්‍ය
-ඥ්‍ය
-ඦ්‍ය
-ට්‍ය
-ඨ්‍ය
-ඩ්‍ය
-ඪ්‍ය
-ණ්‍ය
-ඬ්‍ය
-ත්‍ය
-ථ්‍ය
-ද්‍ය
-ධ්‍ය
-න්‍ය
-ඳ්‍ය
-ප්‍ය
-ඵ්‍ය
-බ්‍ය
-භ්‍ය
-ම්‍ය
-ඹ්‍ය
-ය්‍ය
-ර්‍ය
-ල්‍ය
-ව්‍ය
-ශ්‍ය
-ෂ්‍ය
-ස්‍ය
-හ්‍ය
-ළ්‍ය
-ෆ්‍ය
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index fd5e6e68b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
deleted file mode 100644
index c72be69e0..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-தமிழ்நாடு
-ஓர்
-இந்திய
-மாநிலமாகும்.
-தமிழ்நாடு,
-தமிழகம்
-என்றும்
-பரவலாக
-அழைக்கப்படுகிறது.
-ஆங்கிலத்தில்
-மெட்ராஸ்
-ஸ்டேட்
-என்றும்
-தமிழில்
-சென்னை
-ராஜ்ஜியம்
-என்றும்
-அழைக்கப்பெற்றது.
-இதனை
-தமிழ்நாடு
-என்று
-மாற்றக்கோரி
-போராட்டங்கள்
-நடைபெற்றன.
-சங்கரலிங்கனார்
-என்பவர்
-நாட்கள்
-உண்ணாவிரதம்
-இருந்து
-உயிர்துறந்தார்.
-பின்னர்
-மதராசு
-ஸ்டேட்
-என்று
-இருந்த
-பெயர்
-ஆம்
-ஆண்டு
-தமிழ்நாடு
-என்று
-மாற்றப்பட்டது.
-ஸ்ரீ
-க்ஷ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 7a265103b..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-க
-ங
-ச
-ஜ
-ஞ
-ட
-ண
-த
-ந
-ன
-ப
-ம
-ய
-ர
-ற
-ல
-ள
-ழ
-வ
-ஶ
-ஷ
-ஸ
-ஹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
deleted file mode 100644
index f70ba6afa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
+++ /dev/null
@@ -1 +0,0 @@
-௹
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index f22470cdf..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-ா
-ி
-ீ
-ு
-ூ
-ெ
-ே
-ை
-ொ
-ோ
-ௌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 47b1d621f..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-௦
-௧
-௨
-௩
-௪
-௫
-௬
-௭
-௮
-௯
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 3940ad3a6..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-அ
-ஆ
-இ
-ஈ
-உ
-ஊ
-எ
-ஏ
-ஐ
-ஒ
-ஓ
-ஔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
deleted file mode 100644
index 33f6850bf..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-௰
-௱
-௲
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
deleted file mode 100644
index a7d89e8fa..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-௳
-௴
-௵
-௶
-௷
-௸
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
deleted file mode 100644
index 2d4bdc199..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
+++ /dev/null
@@ -1 +0,0 @@
-௺
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index 49c469c96..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ஂ
-ஃ
-்
-ௗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 40b2b2185..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-கி
-ஙி
-சி
-ஜி
-ஞி
-டி
-ணி
-தி
-நி
-னி
-பி
-மி
-யி
-ரி
-றி
-லி
-ளி
-ழி
-வி
-ஷி
-ஸி
-ஹி
-கீ
-ஙீ
-சீ
-ஜீ
-ஞீ
-டீ
-ணீ
-தீ
-நீ
-னீ
-பீ
-மீ
-யீ
-ரீ
-றீ
-லீ
-ளீ
-ழீ
-வீ
-ஷீ
-ஸீ
-க்
-ங்
-ச்
-ஜ்
-ஞ்
-ட்
-ண்
-த்
-ந்
-ன்
-ப்
-ம்
-ய்
-ர்
-ற்
-ல்
-ழ்
-வ்
-ஷ்
-ஸ்
-ஹ்
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644
index 847495a32..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-கு
-ஙு
-சு
-ஜு
-ஞு
-டு
-ணு
-து
-நு
-னு
-பு
-மு
-யு
-ரு
-று
-லு
-ளு
-ழு
-வு
-ஷு
-ஸு
-ஹு
-கூ
-ஙூ
-சூ
-ஜூ
-ஞூ
-டூ
-ணூ
-தூ
-நூ
-னூ
-பூ
-மூ
-யூ
-ரூ
-றூ
-லூ
-ளூ
-ழூ
-வூ
-ஷூ
-ஸூ
-ஹூ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 2ca1df34e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-க்ஷ
-க்ஷி
-க்ஷீ
-ஷ்ரீ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
deleted file mode 100644
index ff522d2d1..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-కై
-క్
-క్కై
-క్ర
-క్రి
-క్రై
-క్ర్
-క్ర్క
-క్ష
-క్ష్
-క్ష్ణ
-ఽం
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
deleted file mode 100644
index c3cfc84cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-ఓ ఒౕ
-ఔ ఒౌ
-ీ ిౕ
-ే ెౕ
-ో ొౕ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
deleted file mode 100644
index 2cf82282c..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README
deleted file mode 100644
index 8bad3379e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
deleted file mode 100644
index 0ed1a89cd..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644
index a92b179ef..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ౠ
-ౡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644
index 9b8ff6997..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-క
-ఖ
-గ
-ఘ
-ఙ
-చ
-ఛ
-జ
-ఝ
-ఞ
-ట
-ఠ
-డ
-ఢ
-ణ
-త
-థ
-ద
-ధ
-న
-ప
-ఫ
-బ
-భ
-మ
-య
-ర
-ఱ
-ల
-ళ
-వ
-శ
-ష
-స
-హ
-ఁ
-ం
-ః
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644
index b48ed5d49..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-ా
-ి
-ీ
-ు
-ూ
-ృ
-ౄ
-ె
-ే
-ై
-ొ
-ో
-ౌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644
index 8751b4020..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-౦
-౧
-౨
-౩
-౪
-౫
-౬
-౭
-౮
-౯
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644
index 53c6daf53..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-అ
-ఆ
-ఇ
-ఈ
-ఉ
-ఊ
-ఋ
-ఌ
-ఎ
-ఏ
-ఐ
-ఒ
-ఓ
-ఔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644
index 66a7ca4db..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644
index ebefb52e2..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-ఁ
-ం
-ః
-్
-ౕ
-ౖ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644
index 939e44a15..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
+++ /dev/null
@@ -1,385 +0,0 @@
-కా
-ఖా
-గా
-ఘా
-ఙా
-చా
-ఛా
-జా
-ఝా
-ఞా
-టా
-ఠా
-డా
-ఢా
-ణా
-తా
-థా
-దా
-ధా
-నా
-పా
-ఫా
-బా
-భా
-మా
-యా
-రా
-ఱా
-లా
-ళా
-వా
-శా
-షా
-సా
-హా
-కి
-ఖి
-గి
-ఘి
-ఙి
-చి
-ఛి
-జి
-ఝి
-ఞి
-టి
-ఠి
-డి
-ఢి
-ణి
-తి
-థి
-ది
-ధి
-ని
-పి
-ఫి
-బి
-భి
-మి
-యి
-రి
-ఱి
-లి
-ళి
-వి
-శి
-షి
-సి
-హి
-కీ
-ఖీ
-గీ
-ఘీ
-ఙీ
-చీ
-ఛీ
-జీ
-ఝీ
-ఞీ
-టీ
-ఠీ
-డీ
-ఢీ
-ణీ
-తీ
-థీ
-దీ
-ధీ
-నీ
-పీ
-ఫీ
-బీ
-భీ
-మీ
-యీ
-రీ
-ఱీ
-లీ
-ళీ
-వీ
-శీ
-షీ
-సీ
-హీ
-కె
-ఖె
-గె
-ఘె
-ఙె
-చె
-ఛె
-జె
-ఝె
-ఞె
-టె
-ఠె
-డె
-ఢె
-ణె
-తె
-థె
-దె
-ధె
-నె
-పె
-ఫె
-బె
-భె
-మె
-యె
-రె
-ఱె
-లె
-ళె
-వె
-శె
-షె
-సె
-హె
-కే
-ఖే
-గే
-ఘే
-ఙే
-చే
-ఛే
-జే
-ఝే
-ఞే
-టే
-ఠే
-డే
-ఢే
-ణే
-తే
-థే
-దే
-ధే
-నే
-పే
-ఫే
-బే
-భే
-మే
-యే
-రే
-ఱే
-లే
-ళే
-వే
-శే
-షే
-సే
-హే
-కై
-ఖై
-గై
-ఘై
-ఙై
-చై
-ఛై
-జై
-ఝై
-ఞై
-టై
-ఠై
-డై
-ఢై
-ణై
-తై
-థై
-దై
-ధై
-నై
-పై
-ఫై
-బై
-భై
-మై
-యై
-రై
-ఱై
-లై
-ళై
-వై
-శై
-షై
-సై
-హై
-కొ
-ఖొ
-గొ
-ఘొ
-ఙొ
-చొ
-ఛొ
-జొ
-ఝొ
-ఞొ
-టొ
-ఠొ
-డొ
-ఢొ
-ణొ
-తొ
-థొ
-దొ
-ధొ
-నొ
-పొ
-ఫొ
-బొ
-భొ
-మొ
-యొ
-రొ
-ఱొ
-లొ
-ళొ
-వొ
-శొ
-షొ
-సొ
-హొ
-కో
-ఖో
-గో
-ఘో
-ఙో
-చో
-ఛో
-జో
-ఝో
-ఞో
-టో
-ఠో
-డో
-ఢో
-ణో
-తో
-థో
-దో
-ధో
-నో
-పో
-ఫో
-బో
-భో
-మో
-యో
-రో
-ఱో
-లో
-ళో
-వో
-శో
-షో
-సో
-హో
-కౌ
-ఖౌ
-గౌ
-ఘౌ
-ఙౌ
-చౌ
-ఛౌ
-జౌ
-ఝౌ
-ఞౌ
-టౌ
-ఠౌ
-డౌ
-ఢౌ
-ణౌ
-తౌ
-థౌ
-దౌ
-ధౌ
-నౌ
-పౌ
-ఫౌ
-బౌ
-భౌ
-మౌ
-యౌ
-రౌ
-ఱౌ
-లౌ
-ళౌ
-వౌ
-శౌ
-షౌ
-సౌ
-హౌ
-కఁ
-ఖఁ
-గఁ
-ఘఁ
-ఙఁ
-చఁ
-ఛఁ
-జఁ
-ఝఁ
-ఞఁ
-టఁ
-ఠఁ
-డఁ
-ఢఁ
-ణఁ
-తఁ
-థఁ
-దఁ
-ధఁ
-నఁ
-పఁ
-ఫఁ
-బఁ
-భఁ
-మఁ
-యఁ
-రఁ
-ఱఁ
-లఁ
-ళఁ
-వఁ
-శఁ
-షఁ
-సఁ
-హఁ
-క్
-ఖ్
-గ్
-ఘ్
-ఙ్
-చ్
-ఛ్
-జ్
-ఝ్
-ఞ్
-ట్
-ఠ్
-డ్
-ఢ్
-ణ్
-త్
-థ్
-ద్
-ధ్
-న్
-ప్
-ఫ్
-బ్
-భ్
-మ్
-య్
-ర్
-ఱ్
-ల్
-ళ్
-వ్
-శ్
-ష్
-స్
-హ్
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644
index 50b630b2e..000000000
--- a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
+++ /dev/null
@@ -1,287 +0,0 @@
-క్క
-క్ఖ
-క్గ
-క్ఘ
-క్ఙ
-క్చ
-క్ఛ
-క్జ
-క్ఝ
-క్ఞ
-క్ట
-క్ఠ
-క్డ
-క్ఢ
-క్ణ
-క్త
-క్థ
-క్ద
-క్ధ
-క్న
-క్ప
-క్ఫ
-క్బ
-క్భ
-క్మ
-క్య
-క్ర
-క్ఱ
-క్ల
-క్ళ
-క్వ
-క్శ
-క్ష
-క్స
-క్హ
-త్క
-త్ఖ
-త్గ
-త్ఘ
-త్ఙ
-త్చ
-త్ఛ
-త్జ
-త్ఝ
-త్ఞ
-త్ట
-త్ఠ
-త్డ
-త్ఢ
-త్ణ
-త్త
-త్థ
-త్ద
-త్ధ
-త్న
-త్ప
-త్ఫ
-త్బ
-త్భ
-త్మ
-త్య
-త్ర
-త్ఱ
-త్ల
-త్ళ
-త్వ
-త్శ
-త్ష
-త్స
-త్హ
-న్క
-న్ఖ
-న్గ
-న్ఘ
-న్ఙ
-న్చ
-న్ఛ
-న్జ
-న్ఝ
-న్ఞ
-న్ట
-న్ఠ
-న్డ
-న్ఢ
-న్ణ
-న్త
-న్థ
-న్ద
-న్ధ
-న్న
-న్ప
-న్ఫ
-న్బ
-న్భ
-న్మ
-న్య
-న్ర
-న్ఱ
-న్ల
-న్ళ
-న్వ
-న్శ
-న్ష
-న్స
-న్హ
-మ్క
-మ్ఖ
-మ్గ
-మ్ఘ
-మ్ఙ
-మ్చ
-మ్ఛ
-మ్జ
-మ్ఝ
-మ్ఞ
-మ్ట
-మ్ఠ
-మ్డ
-మ్ఢ
-మ్ణ
-మ్త
-మ్థ
-మ్ద
-మ్ధ
-మ్న
-మ్ప
-మ్ఫ
-మ్బ
-మ్భ
-మ్మ
-మ్య
-మ్ర
-మ్ఱ
-మ్ల
-మ్ళ
-మ్వ
-మ్శ
-మ్ష
-మ్స
-మ్హ
-య్క
-య్ఖ
-య్గ
-య్ఘ
-య్ఙ
-య్చ
-య్ఛ
-య్జ
-య్ఝ
-య్ఞ
-య్ట
-య్ఠ
-య్డ
-య్ఢ
-య్ణ
-య్త
-య్థ
-య్ద
-య్ధ
-య్న
-య్ప
-య్ఫ
-య్బ
-య్భ
-య్మ
-య్య
-య్ర
-య్ఱ
-య్ల
-య్ళ
-య్వ
-య్శ
-య్ష
-య్స
-య్హ
-ర్క
-ర్ఖ
-ర్గ
-ర్ఘ
-ర్ఙ
-ర్చ
-ర్ఛ
-ర్జ
-ర్ఝ
-ర్ఞ
-ర్ట
-ర్ఠ
-ర్డ
-ర్ఢ
-ర్ణ
-ర్త
-ర్థ
-ర్ద
-ర్ధ
-ర్న
-ర్ప
-ర్ఫ
-ర్బ
-ర్భ
-ర్మ
-ర్య
-ర్ర
-ర్ఱ
-ర్ల
-ర్ళ
-ర్వ
-ర్శ
-ర్ష
-ర్స
-ర్హ
-ల్క
-ల్ఖ
-ల్గ
-ల్ఘ
-ల్ఙ
-ల్చ
-ల్ఛ
-ల్జ
-ల్ఝ
-ల్ఞ
-ల్ట
-ల్ఠ
-ల్డ
-ల్ఢ
-ల్ణ
-ల్త
-ల్థ
-ల్ద
-ల్ధ
-ల్న
-ల్ప
-ల్ఫ
-ల్బ
-ల్భ
-ల్మ
-ల్య
-ల్ర
-ల్ఱ
-ల్ల
-ల్ళ
-ల్వ
-ల్శ
-ల్ష
-ల్స
-ల్హ
-వ్క
-వ్ఖ
-వ్గ
-వ్ఘ
-వ్ఙ
-వ్చ
-వ్ఛ
-వ్జ
-వ్ఝ
-వ్ఞ
-వ్ట
-వ్ఠ
-వ్డ
-వ్ఢ
-వ్ణ
-వ్త
-వ్థ
-వ్ద
-వ్ధ
-వ్న
-వ్ప
-వ్ఫ
-వ్బ
-వ్భ
-వ్మ
-వ్య
-వ్ర
-వ్ఱ
-వ్ల
-వ్ళ
-వ్వ
-వ్శ
-వ్ష
-వ్స
-వ్హ
-స్త్ర
-స్త్రి
-స్త్రీ
-ష్ట్ర
-షటరీ
-క్ష్మ
-క్ష్మి
diff --git a/test/shape/texts/in-house/shaper-khmer/misc.txt b/test/shape/texts/in-house/shaper-khmer/misc.txt
deleted file mode 100644
index 3bbffe7ee..000000000
--- a/test/shape/texts/in-house/shaper-khmer/misc.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-ខ្មែ
-ជា
-ថ្ងៃ
-មា
-ម្ពុ
-រ
-រី
-រ៍
-សៅ
-រ្ឥ
-ងឹ្ឈ
-ង្ឈឹ
-ង្គ្រ
-ង្រ្គ
-ម៉្លេះ
-ម‌៉្លេះ
-ប៊័
-នែ៎
-កេ្រ
-កៀ្រ
-កោ្រ
-កៅ្រ
-ព៑ា
-កន្ត្រាក់
-កន្រ្សិក់
-កន្រ្សីក់
-ក្សាន្ត
-ក្សិន្ត
-ក្សីន្ត
-ក្សឹន្ត
-ក្សឺន្ត
-ក្សុន្ត
-ក្សូន្ត
-ក្សួន្ត
-ក្សឿន្ត
-ឃ្ល្សាំ
-ឃ្ល្សិះ
-ឃ្ល្សុំ
-ឃ្ល្សុះ
-ឃ្ល្សេះ
-ឃ្ល្សោះ
-ឃ្ល្សំ
-ឃ្ល្សះ
-ញូ
-ញ្ញ
-ញ្ញុ
-ញ្ញូ
-ញ្ញួ
-ត្រ្សៀ
-ត្រ្សេ
-ត្រ្សែ
-ត្រ្សៃ
-ត្រ្សោ
-ត្រ្សៅ
-ធ្លុំក់
-ធ្លោក់
-ធ្លៅក់
-ធ្លំក់
-ម្ត្ល៉ា
-ម្ត្ល៉ុ
-ម្ត្ល៉ឿ
-ម្ត្ល៉ៀ
-យ្យើហ្វ្លៃ
-រ្រ
-សាស្ត្រឃ្ឈងា
-សាស្ត្រឃ្ឈងិ
-សាស្ត្រឃ្ឈងី
-ស្ត្រីវ័ខ្ញ្សា
-ស្រ្តា
-ស្រ្តិ
-ស្រ្តី
-ស្រ្តឹ
-ស្រ្តឺ
-ស្រ្តុ
-ស្រ្តូ
-ស្រ្តួ
-ស្រ្តើ
-ស្រ្តឿ
-ស្រ្ត៊ឿ
-ស្រ្ត៊ៀ
-ស្រ្ត៊េ
-ស្រ្ត៊ែ
-ស្រ្ត៊ៃ
-ស្រ្ត៊ំ
-ហ្គ្ស៊ើ
-ហ្គ្ស៊ឿ
-ហ្គ្ស៊ៀ
-ហ្រ្វង្ក
-ហ្រ្វាំង
diff --git a/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt b/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt
deleted file mode 100644
index 213cfc29a..000000000
--- a/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ព់្ឈា
-ព្ឈា៉
-ព្ឈា៌
-ព្ឈ៌ា
diff --git a/test/shape/texts/in-house/shaper-khmer/other-marks.txt b/test/shape/texts/in-house/shaper-khmer/other-marks.txt
deleted file mode 100644
index 1fd350c73..000000000
--- a/test/shape/texts/in-house/shaper-khmer/other-marks.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-ព្ឈា
-ព្ឈា់
-ព្ឈ់ា
-ព្ឈ៉ា
-ព៉្ឈា
-ព៌្ឈា
-ក៝ៈនូយ្សក៝ៈនហ៝ម់
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
deleted file mode 100644
index 9dc6332a4..000000000
--- a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည် အာယုဝဍ္ဎနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေးဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်။
-။း
-င်္၎
-နၣ်
-နၢၣ်
-ဂ်ျ
-ဂျ်
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
deleted file mode 100644
index e3d460de6..000000000
--- a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
+++ /dev/null
@@ -1 +0,0 @@
-င်္က္ကျြွှေို့်ာှီ့ၤဲံ့းႍ
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
deleted file mode 100644
index d5cea7c17..000000000
--- a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-စာ
-ခါ
-သိက္ခာ
-သဒ္ဓါ
-ညို
-ထုံး
-နေ
-ပေါ
-ဖျား
-ကြေး
-မွေး
-မှု
-ပတ္တာ
-ထင်
-ကြဉ်
-ကော်
-စင်္ကြံ
-သင်္ဘော
-ပသျှူး
-မြွှာ
-သျှောင်
-ကောင်လေးတွေကျောင်းကိုသွားကြတယ်။
-အိပ်ခန်းတံခါးကို
-အိပ်ခန်းတံ⁠ခါးကို
-အင်္ဝေ
-အငွေ
-ယောက်ျား
-ကျွန်ုပ်
-ဝါကျ
-ဂိမှာန်
-ဥယ‌ျာန
-က္လ
-ကျ္လပ်
-နိယ္အ်
diff --git a/test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt b/test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt
deleted file mode 100644
index 234d8c06e..000000000
--- a/test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-ດຳ
-ດ໋ຳ
-ດໍ໋າ
-ດ໋ໍາ
-ມັຳ
-ມິຳ
-ມີຳ
-ມຶຳ
-ມືຳ
-ມຸຳ
-ມູຳ
-ມ຺ຳ
-ມ໇ຳ
-ມ່ຳ
-ມ້ຳ
-ມ໊ຳ
-ມ໋ຳ
-ມ໌ຳ
-ມໍຳ
-ມ໎ຳ
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt
deleted file mode 100644
index b4f164baf..000000000
--- a/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-ป่ำ
-ป่ำซ้ำพ่อปู่พี่ปี่ฎุฐุญุ
-ก่ํา
-กํ่า
-กุเ
-กะ
-ก่ื
-กื
-กำ
-ก่ำ
-ก่
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
deleted file mode 100644
index e304777ca..000000000
--- a/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-ป
-ปฺ
-ปุ
-ปู
-ปุู
-ปูุ
-ปฺุ
-ปฺุ
-ปฺู
-ปฺู
-ปฺุู
-ปฺุู
-ปฺุู
-ปฺูุ
-ปฺูุ
-ปฺูุ
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt
deleted file mode 100644
index c17834ba6..000000000
--- a/test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-นี
-น่
-นี่
-น่ี
-ป็
-ญ
-ญุ
-ฝิ
-ฝิ่
-ฝ่
-ฎู
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt
deleted file mode 100644
index 9f044ce84..000000000
--- a/test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-ดำ
-ด๋ำ
-ดํ๋า
-ด๋ํา
-มัำ
-มิำ
-มีำ
-มึำ
-มืำ
-มุำ
-มูำ
-มฺำ
-ม็ำ
-ม่ำ
-ม้ำ
-ม๊ำ
-ม๋ำ
-ม์ำ
-มํำ
-ม๎ำ
diff --git a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
deleted file mode 100644
index 46da1af62..000000000
--- a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
+++ /dev/null
@@ -1,612 +0,0 @@
-ཀི་ཀང་
-ཀྐིང་
-ཀི་ཀི་སྭོ་སྭོ་
-ཀིི་སྭོོ་
-ཀུན་དཀྲིས་
-ཀིུས་
-ཀུན་མཁྱེན་
-ཀེུན་
-ཀུན་དགའ་
-ཀུནའ་
-ཀུན་འཇོམས་
-ཀུནོམས་
-ཀུན་བརྡུངས་
-ཀུནྡུང་
-ཀུན་ནས་
-ཀུནྶ་
-ཀུན་རྫོབ་
-ཀོུབ༹་
-ཀུན་གཟིགས་
-ཀིུགས་
-ཀུན་བཟང་
-ཀུན༹ང་
-ཀུན་ཤེས་
-ཀེུས་
-ཀླུ་ཐེབས་
-ཀླེུབས་
-ཀླུ་ཟློག་
-ཀློུག་
-དཀར་པོ་
-དཀརོ་
-དཀར་ཡོལ་
-དཀོལ་
-དཀོན་མཆོག་
-དཀོོག་
-དཀོར་ནོར་
-དཀོོར་
-དཀྱིལ་འཁོར་
-དཀྱོིར་
-བཀའ་དྲིན་
-བཀྲིན་
-བཀྲ་ཤིས་
-བཀྲིས་
-བཀྲ་ཤིས་ཉི་མ་
-བཀྲིསྙི་
-སྐལ་བཟང་
-སྐལ༹ང་
-སྐུ་གསུང་ཐུགས་
-སྐུགས་
-སྐྱེ་རྒུ་
-སྐྱེུ་
-སྐྱེ་མཆེད་
-སྐྱེདེ་
-བསྐྱེད་བསྐྱེད་
-བསྐྱེེད་
-བསྐྱེད་བསྐྱེད་བསྐྱེད་
-བསྐྱེེེད་
-ཁམས་གསུམ་
-ཁམསུཾ་
-ཁུར་ཚོས་
-ཁོུས༹་
-ཁྱད་པར་
-ཁྱདར་
-ཁྱབ་བདག་
-ཁྱབདག་
-ཁྱུ་མཆོག་
-ཁྱོུག་
-ཁྲུན་མེད་
-ཁྲེུད་
-ཁྲུན་རིང་
-ཁྲིུང་
-ཁྲུམས་སྟོད་
-ཁྲོུད་
-ཁྲུམས་སྨད་
-ཁྲུཾད་
-མཁའ་འགྲོ་
-མཁའགྲོ་
-མཁྱེན་མཁྱེན་མཁྱེན་
-མཁྱེེེན་
-འཁོར་འདས་
-འཁོརས་
-འཁོར་བཅས་
-འཁོརས་
-འཁོར་ལོ་
-འཁོོར་
-གུར་ཐོག་
-གོུག་
-གྱུར་ཅིག་
-གྱིུག་
-གྲུ་འཛིན་
-གྲིུན་
-གྲུ་བཞི་
-གྲིུ་
-གྲུ་ཡོན་
-གྲོུན་
-གྲུབ་ཉི་
-གྲུབྙི་
-གྲུབ་ཐོབ་
-གྲོུབ་
-གྲོ་བཞིན་
-གྲོིན་
-གྲོང་ཁྱེར་
-གྲོེར་
-གླང་པོ་
-གླངོ་
-གླེགས་བམ་
-གླེམ་
-དགུང་ཐིག་
-དགིུག་
-དགེ་འདུན་
-དགེུན་
-དགེ་ལུགས་
-དགེུགས་
-དགེ་སློང་
-དགློེང་
-དགྲ་བགེགས་
-དགྲེགས་
-དགྲ་བཅོམ་
-དགྲོམ་
-མགོན་པོ་
-མགོོན་
-འགྲུབ་བྱ་
-འགྲུབྱ་
-འགྲུབ་སྦྱོར་
-འགྲུབྱོར་
-རྒ་ཤི་
-རྒི་
-རྒུན་འབྲུམ་
-རྒྲུམ་
-རྒྱ་མཚོ་
-རྪོ་
-རྒྱལ་པོ་
-རྒྱོལ་
-རྒྱལ་བློན་
-རྒྱལོན་
-རྒྱལ་མཚན་
-རྒྱལ༹ན་
-ངན་ཀྱང་
-ངནྱང་
-ངུར་སྨྲིག་
-ངིུག་
-དངོས་གྲུབ་
-དགྲོུབ་
-གཅུ་གལ་
-གཅུལ་
-བཅུ་གཅིག་
-བཅིུག་
-བཅུ་གཉིས་
-བཅིུས་
-བཅུ་དྲུག་
-བཅྲུག་
-བཅུ་བདུན་
-བཅུན་
-བཅུ་བཞི་
-བཅིུ་
-བཅུ་གསུམ་
-བཅུཾ་
-བཅོ་བརྒྱད་
-བཅྱོད་
-བཅོམ་ལྡན་
-བཅོནཾ་
-བཅོམ་ལྡན་འདས་
-བཅོནྡས་
-ལྕགས་
-ལྕཊ་
-ལྕགས་སྒྲོག་
-ལྕགསྒྲོག་
-ཆ་ཤེས་
-ཆེས་
-ཆགས་ཐོགས་
-ཆཊ་ཐོཊ་
-ཆད་
-ཆྡ་
-ཆུ་དཀྱིལ་
-ཆིུལ་
-ཆུ་སྟོད་
-ཆོུད་
-ཆུ་སྣོད་
-ཆོུད་
-ཆུ་སྨད་
-ཆུཾད་
-ཆུ་ཚོད་
-ཆོུ༹ད་
-ཆུ་སྲིན་
-ཆྲིུན་
-ཆུབ་ཉི་
-ཆུབྙི་
-ཆོ་འཕྲུལ་
-ཆྲོུལ་
-ཆོས་སྤྱོད་
-ཆོསྤྱོད་
-མཆོད་རྟེན་
-མཆོེན་
-འཆི་བདག་
-འཆྡིག་
-འཆི་སྦྱོར་
-འཆྱོིར་
-ཇོ་བོ་
-ཇོོ་
-ཇོ་མོ་
-ཇོོ་
-ཇོ་ཇོ་
-ཇོོ་
-འཇིག་ཉི་
-འཇིགྙི་
-འཇིག་རྟེན་
-འཇིགེན་
-རྗེ་བཙུན་
-རྗེུན༹་
-ཉན་ཐོས་
-ཉནོས་
-ཉི་ཤུ་
-ཉིུ་
-ཉིན་གུང་
-ཉིུང་
-ཉིན་ནག་
-ཉིནག་
-ཉིན་ཚད་
-ཉིན༹ད་
-ཉིན་མཚན་
-ཉི༹ན་
-ཉེར་གཅིག་
-ཉྲེ་གཅིག་
-ཉོན་མོངས་
-ཉོནོངས་
-མཉན་ཡོད་
-མཉོད་
-མཉམ་ཉིད་
-མཉིཾད་
-མཉམ་བཞག་
-མཉཾག་
-སྙིང་རྗེ་
-སྙིངེ་
-བསྙེན་བཀུར་
-བསྙུར་
-ཏིང་འཛིན་
-ཏིངི༹ན་
-གཏི་མུག་
-གཏིུག་
-གཏུན་ཤིང་
-་གཏུནིང་
-གཏུམ་མོ་
-གཏུམོ་
-བཏང་སྙོམས་
-བཏངོཾས་
-རྟག་ཏུ་
-རྟགྟུ་
-སྟག་སྨྱོས་
-སྟྱོས་
-སྟོབས་རྒྱས་
-སྟོབྱས་
-བསྟན་འཛིན་
-བསྟི༹ན་
-ཐམ་པ་
-ཐཾ་པ་
-ཐམས་ཅད་
-ཐཾད་
-ཐུགས་རྗེ་
-ཐུཊེ་
-ཐུགས་བརྩེ་
-ཐེུ༹ཊ་
-ཐུན་མོང་
-ཐུནོང་
-ཐུན་བཞི་
-ཐིུན་
-ཐེག་ཆེན་
-ཐེགེན་
-མཐའ་འཁོབ་
-མཐོབ་
-མཐའ་དག་
-མཐྡག་
-མཐར་ཕྱིན་
-མཐྱིན་
-མཐུན་མོང་
-མཐོུང་
-མཐེ་བོང་
-མཐོེང་
-མཐོ་རིས་
-མཐོིས་
-དུར་ཁྲོད་
-དུརྲོད་
-དུས་དབྱིགས་
-དུསྱིགས་
-དུས་སུ་
-དུསུ་
-དེ་བཞིན་གཤེགས་པ་
-དེནིཊེ་པ་
-དྲག་པོ་
-དྲགོ་
-དྲག་ཤོས་
-དྲགོས་
-དྲང་སྲོང་
-དྲོང་
-དྲུང་དུ་
-དྲུངྡུ་
-དྲུང་ཡིག་
-དྲིུག་
-གདུང་རྟེན་
-གདེུན་
-གདུང་འཛིན་
-གདིུ༹ན་
-གདུབ་བུ་
-གདུབུ་
-བདུག་སྤོས་
-བདོུས་
-བདུད་རྒྱལ་
-བདུདྱལ་
-བདུད་ཉི་
-བདུདྙི་
-བདུད་རྩི་
-བདུདི༹་
-བདེ་ཆེན་
-བདེནེ་
-བདེ་གཤེགས་
-བདཻགས་
-འདུ་བྱེད་
-འདེུད་
-རྡོ་རྗེ་
-རྡོེ་
-སྡིག་སྲིན་
-སྡིན་
-སྡིགས་མཛུབ་
-སྡིུབ་
-སྡུག་བསྔལ་
-སྡུགལ་
-ནབས་སོ་
-ནབསོ་
-ནམ་མཁའ་
-ནམཁའ་
-ནམ་གྲུ་
-ནམྲུ་
-ནུབ་ཕྱོགས་
-ནོུགས་
-ནོར་བུ་
-ནོུར་
-གནམ་སྦྱོར་
-གནྱོཾར་
-གནས་སྐབས་
-གནསྐབས་
-རྣམ་གྲངས་
-རྣངཾས་
-རྣམ་ཤེས་
-རྣཾསེ་
-རྣམས་
-རྣཾས་
-རྣལ་འབྱོར་
-རྣལྱོར་
-སྣ་ཚོགས་
-སྣོ༹གས་
-པི་ལིང་
-པླིང་
-དཔག་མེད་
-དཔགེད་
-དཔལ་ལྡན་
-དཔལྡན་
-དཔལ་བེའུ་
-དཔལེ་
-དཔལ་འབྱོར་
-དཔལྱོར་
-དཔུང་ཚོགས་
-དཔོུགས་
-དཔེ་བྱད་
-དཔྱེད་
-སྤྱན་རས་གཟིགས་
-སྤྱས་གཟིགས་
-སྤྲོས་བྲལ་
-སྤྲོལ་
-ཕན་གནོད་
-ཕནོད་
-ཕུན་ཚོགས་
-ཕུགས་
-ཕོ་ཉ་
-ཕྙོ་
-ཕོ་རོལ་
-ཕརོལ་
-ཕྱག་འཚལ་ལོ་
-ཕྱ༹ལོ་
-ཕྲག་དོག་
-ཕྲོག་
-ཕྲིན་ལས་
-ཕྲིས་
-འཕེལ་ཉི་
-འཕེལྙི་
-འཕྲིན་ལས་
-ཕྲིས་
-བར་ཆད་
-བརད་
-བུ་མོ་
-བོུ་
-བུད་མེད་
-བེུད་
-བུད་ཤིང་
-བིུང་
-བོང་བུ་
-བོུང་
-བྱ་ཚོགས་
-བྱོ༹གས་
-བྱ་རོག་
-བྱོག་
-བྱང་ཆུབ་
-བྱུཾབ་
-བྱང་ཕྱོགས་
-བྱོགས་
-བྱི་བཞིན་
-བྱིནི་
-བྱོལ་སོང་
-བྱོང་
-བྲམ་ཟེ་
-བྲེམ་
-བླུན་པོ་
-བློུན་
-བློ་གྲོས་
-བློས་
-བློན་པོ་
-བློོན་
-དབང་པོ་
-དབངོ་
-དབང་ཕྱུག་
-དབྱུག་
-དབུ་ཐོད་
-དབོུད་
-དབུགས་ཐོབ་
-དབོུབས་
-དབྱེར་མེད་
-དབྱེརེད་
-འབྲས་བུ་
-འབྲུས་
-སྦྱོར་ཉི་
-སྦྱོརྙི་
-སྦྲང་རྩི་
-སྦྲིང༹་
-མ་རིག་
-མྲིག་
-མི་འཕྲོད་ཉི་
-མི་འཕྲོདྙི་
-མིག་དམར་
-མིར་
-མིང་གཟུགས་
-མིངུགས་
-མུ་གེ་
-མེུ་
-མུ་སྙེགས་
-མེུགས་
-མུ་ཏིག་
-མིུག་
-མུ་སྟེགས་
-མེུགས་
-མུ་མེན་
-མེུན་
-མེ་ཏོག་
-མྟོེག་
-མེ་ལོང་
-མོེང་
-མོན་གྲུ་
-མོནྲུ་
-མོན་དྲེ་
-མོནྲེ་
-མྱ་ངན་
-མྱན་
-དམག་དཔུང་
-དམུང་
-དམག་དཔོན་
-དམོན་
-སྨིན་དྲུག་
-སྨིནྲུག་
-ཙན་དན་
-ཙྡན་
-གཙུག་ཏོར་
-གཙོུར་
-རྩ་བཏོན་
-རྩོན་
-བརྩོན་འགྲུས་
-བརྩུས་
-ཚུལ་ཁྲིམས་
-ཚུལྲིམས་
-ཚུལ་ལྡན་
-ཚུལྡན་
-ཚེ་ལྡན་
-ཚྡེན་
-མཚན་ཉིད་
-མཚིད་
-མཚན་ཚད་
-མཚན༹ད་
-མཚམས་ཞུས་
-མཚྮུཾས་
-རྫུ་འཕྲུལ་
-རྫྲུལ་
-རྫུས་སྐྱེས་
-རྫེུས་
-རྫེ་བཙུན་
-རྫེུན་
-ཞུ་གསོལ་
-ཞོུལ་
-གཞལ་སྒང་
-གཞལྒང་
-གཞུ་ཐོག་
-གཞོུག་
-གཞུ་འདོམས་
-གཞོུམས་
-གཞོན་ནུ་
-གཞོནུ་
-གཟུ་བོ་
-གཟོུ་
-གཟུ་ཤིང་
-གཟིུང་
-གཟུག་གིན་འདུག་
-གཟུགིན་འདུག་
-གཟུག་ཟེར་
-གཟེུར་
-གཟུག་གཟེར་
-གཟེུར་
-གཟུགས་སྐུ་
-གཟུགསྐུ་
-གཟུགས་སྡུག་
-གཟུགསྡུག་
-གཟུགས་མེད་
-གཟེུད་
-འོད་དཀར་
-འོདཀར་
-འོད་ཟེར་
-འོེར་
-ཡན་ལག་
-ཡནག་
-ཡི་གེ་
-ཡིེ་
-ཡིན་ནམ་
-ཡིནམ་
-ཡེ་ཤེས་
-ཡེེས་
-ཡོན་ཏན་
-ཡྟོན་
-རབ་བྱུང་
-རབྱུང་
-རལ་གྲི་
-རལྲི་
-རིན་ཆེན་
-རིནེ་
-རིན་པོ་ཆེ་
-རིནོེ་
-རོང་ཡུལ་
-རོུལ་
-ལང་འཚོ་
-ལངོ༹་
-ལས་བཟང་
-ལསང་
-ལེགས་སྦྱར་
-ལེགསྦྱར་
-ལོངས་སྐུ་
-ལོངསྐུ་
-ལོངས་སྤྱོད་
-ལོངསྤྱོད་
-ཤ་འཁོན་
-ཤྑོན་
-ཤིན་ཏུ་
-ཤིནྟུ་
-ཤེས་བྱ་
-ཤྱེས་
-ཤེས་རབ་
-ཤེབ་
-ས་བོན་
-སོན་
-སངས་རྒྱས་
-སངྱས་
-སེང་གེ་
-སེངྒེ་
-སེམས་
-སྶེ་
-སེམས་ཅན་
-སེཾན་
-སེམས་དཔའ་
-སེཾདའ་
-སོ་སོ་བ་
-སོོབ་
-སོ་སོར་
-སོོར་
-སོགས་
-སོཊ་
-སོམས་ཤིག་
-སོསཾ་ཤིག་
-སྲེག་སྦྱོར་
-སྲེགྱོར་
-སྲེག་ཚེས་
-སྲོེས་
-སློབ་འདོད་
-སློོད་
-སློབ་དཔོན་
-སློོན་
-གསུང་རབ་
-གསུབ་
-བསོད་སྙོམས་
-བསྙོཾདས་
-བསོད་ནམས་
-བསོདཾས་
-ལྷ་ཚོགས་
-ལྷོ༹གས་
-ལྷ་མཚམས་
-ལྷ༹ཾས་
-ལྷག་
-ལྷྒ་
-ལྷན་རྒྱས་
-ལྷྱས་
-ལྷན་ཅིག་
-ལྷིག་
-ལྷན་གཅིག་
-ལྷིག་
-ལྷན་ཚོགས་
-ལྷནོ༹ཊ་
-ལྷུན་གྲུབ་
-ལྷུནྲུབ་
-ལྷོ་ཕྱོགས་
-ལྷྱོགས་
-ཨོ་རྒྱན་
-ཨྱོན་
diff --git a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
deleted file mode 100644
index a5d408219..000000000
--- a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-སྟྲཱ
-ཀ࿆ྃ
diff --git a/test/shape/texts/in-house/shaper-use/script-batak/misc.txt b/test/shape/texts/in-house/shaper-use/script-batak/misc.txt
deleted file mode 100644
index c8ae04bc9..000000000
--- a/test/shape/texts/in-house/shaper-use/script-batak/misc.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-ᯂᯩ
-ᯄ᯦ᯩ
-ᯇᯪᯰ
-ᯓᯩᯰ
-ᯄᯮ
-ᯃᯮ
-ᯎᯮ
-ᯞᯮ
-ᯖᯪᯇ᯲
diff --git a/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt b/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt
deleted file mode 100644
index 5c1a03ad1..000000000
--- a/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt
+++ /dev/null
@@ -1,70 +0,0 @@
-ᨒᨚᨈᨑ
-ᨔᨑ
-ᨅᨔ ᨈᨚ ᨅᨙᨀ
-ᨕᨒᨚ ᨆᨒᨗᨕᨘ ᨅᨛᨈᨘᨕᨊ
-ᨕᨗᨉᨚ ᨔᨘᨑᨛ
-ᨕᨗᨊ ᨔᨘᨑᨛ
-ᨕᨊ ᨔᨘᨑᨛ
-
-ᨊᨀᨚ ᨕᨛᨃ ᨈᨕᨘᨄᨔᨒ᨞ ᨕᨍ ᨆᨘᨄᨈᨒᨒᨚᨓᨗ ᨄᨌᨒᨆᨘ ᨑᨗᨈᨚᨄᨔᨒᨕᨙ᨞
-ᨄᨔᨗᨈᨘᨍᨘᨓᨗᨆᨘᨈᨚᨓᨗᨔ ᨕᨔᨒᨊ ᨄᨌᨒᨆᨘ᨞ ᨕᨄ ᨕᨗᨀᨚᨊᨈᨘ ᨊᨁᨗᨒᨗ ᨉᨙᨓᨈᨕᨙ᨞
-ᨊᨀᨚ ᨅᨕᨗᨌᨘᨆᨘᨄᨗ ᨕᨔᨒᨊ ᨈᨕᨘᨓᨙ᨞ ᨆᨘᨄᨙᨑᨍᨕᨗᨔ ᨄᨉᨈᨚᨓᨗ᨞
-ᨊᨀᨚ ᨄᨔᨒᨕᨗ ᨈᨕᨘᨓᨙ᨞ ᨕᨍ ᨈᨗᨆᨘᨌᨒᨕᨗ ᨑᨗᨔᨗᨈᨗᨊᨍᨊᨕᨙᨈᨚᨔ ᨕᨔᨒᨊ᨞
-
-ᨕᨛᨛᨃ ᨕᨛᨃ ᨄ ᨙᨑ᨞ ᨕᨛᨃ ᨙᨔᨕᨘᨓ ᨓᨛᨈᨘ᨞
-ᨕᨛᨃ ᨙᨔᨕᨘᨓ ᨕᨑᨘ ᨆᨀᨘᨋᨕᨗ ᨑᨗ ᨒᨘᨓᨘ᨞ ᨆᨔᨒ ᨕᨘᨒᨗ᨞
-
-ᨄᨘᨑᨊᨗᨀᨚ ᨆᨙᨋ?
-ᨉᨙᨄ
-
-ᨆᨙᨒᨚ ᨀ ᨌᨛᨙᨆ
-ᨔᨙᨉᨗ
-ᨉᨘᨓ
-ᨈᨛᨒᨘ
-ᨕᨛᨄ
-ᨒᨗᨆ
-ᨕᨛᨊᨛ
-ᨄᨗᨈᨘ
-ᨕᨑᨘᨓ
-ᨕᨙᨔᨑ
-ᨔᨄᨘᨒᨚ
-ᨉᨘᨓᨄᨘᨒᨚ
-ᨈᨛᨒᨘᨄᨘᨒᨚ
-ᨄᨈᨄᨘᨒᨚ
-ᨒᨗᨆᨄᨘᨒᨚ
-ᨕᨛᨊᨛᨄᨘᨒᨚᨊ
-ᨄᨗᨈᨘᨄᨘᨒᨚ
-ᨕᨑᨘᨓᨄᨘᨒᨚᨊ
-ᨕᨙᨔᨑᨄᨘᨒᨚᨊ
-ᨔᨗᨑᨈᨘ
-ᨔᨗᨔᨛᨅᨘ
-ᨔᨗᨒᨔ
-ᨔᨗᨀᨚᨈᨗ
-
-ᨅᨔ ᨕᨘᨁᨗ
-
-ᨅᨔ ᨆᨀᨔᨑ
-ᨅᨒ
-ᨅᨚᨒᨚ
-ᨅᨅ
-ᨌᨗᨄᨘᨑᨘ
-ᨉᨚᨕᨙ
-ᨕᨗᨐᨚ
-ᨒᨚᨄᨚ
-ᨔᨒᨚ
-ᨈ ᨅᨙᨙ
-ᨈᨙᨊ
-ᨀᨑᨕᨙ
-ᨕᨄ ᨀᨑᨙᨅ?
-ᨒᨀᨙᨀᨚ ᨆᨕᨙ?
-ᨅᨒ
-ᨅᨚᨈᨚ
-ᨑᨈᨔ
-ᨅᨈᨒ
-ᨅᨗᨒ
-ᨁᨙᨒᨙ ᨁᨙᨒᨙ
-ᨀᨚᨀᨚ
-ᨍᨑ
-ᨅᨙᨅᨙ
-ᨆᨚᨈᨙᨑᨙ
-ᨂᨑᨙ
diff --git a/test/shape/texts/in-house/shaper-use/script-cham/misc.txt b/test/shape/texts/in-house/shaper-use/script-cham/misc.txt
deleted file mode 100644
index 32b793a09..000000000
--- a/test/shape/texts/in-house/shaper-use/script-cham/misc.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ꩀꨴ
-ꨗꨪꨇꨮꩃꨯꨗꨱꨧꨩꩂꨯꨨꨱꩃꨨꨮ
-ꨆꨴꨯ
diff --git a/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt b/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt
deleted file mode 100644
index 16c3d9c37..000000000
--- a/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-ꦥꦺ
-ꦟ꧀ꦢꦿ
-ꦥꦺꦴꦂꦠꦸꦒꦭ꧀
-꧋
-​꧅
-꧑꧐꧇
-꧒꧐꧐꧔
-꧑꧘꧘꧕꧇
-ꦥꦤꦶꦠꦿ꧇
-ꦏꦠꦿꦁꦔꦤ꧀
-꧅꧉ꦟ꧀ꦢꦿ꧉꧅
-ꦥꦺꦔꦼꦠ꧀ꦠꦤ꧀
-ꦄꦒꦸꦱ꧀ꦠꦸꦱ꧀꧇
-ꦮꦸꦭꦤ꧀ꦗꦤꦸꦮꦫꦶ
-ꦠꦸꦮꦤ꧀​ꦯꦶꦏꦺꦕꦶ
-ꦲꦶꦁ​ꦱꦸꦂꦪ​ꦏꦥꦶꦁ꧇
-ꦯꦺꦟꦦꦡꦶ​ꦲꦶꦁ​ꦔꦭꦓ꧈
-ꦲꦸꦠꦮꦶ​ꦯꦸꦂꦪ​ꦏꦥꦶꦁ꧇
-ꦥꦩꦼꦁꦏꦸꦤꦶꦫꦺꦁ​ꦨꦸꦮꦤ꧈
-ꦩꦁꦏꦾ​ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ꧈
-ꦠꦤ꧀ꦧꦁꦏꦶꦠ꧀ꦲꦔꦸꦕꦥ꧀ꦥꦼꦤ꧈
-ꦠꦸꦮꦤ꧀​ꦈꦤ꧀​ꦕꦸꦤ꧀​ꦲꦺꦴꦏ꧀
-ꦲꦢꦶꦤꦶꦁꦔꦿꦠ꧀ꦏꦿꦡꦺꦴꦤ꧀ꦲꦗꦶ꧈
-ꦥꦔꦿꦺꦃꦲꦶꦁꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀
-ꦠꦼꦤ꧀ꦠꦽꦩ꧀ꦥꦿꦢꦱꦶꦃ​ꦒꦼꦁꦲꦭꦶꦠ꧀
-ꦲꦶꦁꦏꦁ​ꦲꦁꦒꦫꦥ꧀​ꦫꦢꦺꦤ꧀​ꦯꦸꦰꦺꦗ
-ꦫꦢꦺꦤ꧀ꦲꦗꦶꦩ꦳ꦸꦃꦏ꦳ꦩ꦳ꦢ꧀‌ꦔꦢ꧀ꦤꦤ꧀
-ꦮꦸꦭꦤ꧀ꦗꦸꦩꦢꦶꦭꦮꦭ꧀ꦠꦲꦸꦤ꧀ꦗꦶꦩ꧀ꦩꦮꦭ꧀
-ꦑꦭꦶꦦꦡꦸꦭ꧀ꦭꦃ​ꦲꦶꦁꦏꦁ​ꦗꦸꦩꦼꦤꦼꦁ​ꦏꦥꦶꦁ
-ꦠꦤ꧀ꦝꦶꦁꦔꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀꧈
-ꦩꦶꦤꦺꦴꦁꦏ​ꦥꦺꦔꦼꦠ꧀ꦠꦤ꧀ꦗꦸꦩꦼꦤꦼꦁ​ꦢꦊꦩ꧀ꦟꦡ꧈
-ꦏꦑꦒꦓꦔꦕꦖꦗꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦭꦮꦯꦰꦱꦲ
-ꦢꦺꦤ꧀ꦤꦶꦁ​ꦫꦢꦺꦤ꧀ꦔꦤ꧀ꦠꦺꦤ꧀ꦡꦸꦩꦼꦁꦒꦸꦁ​ꦦꦿꦮꦶꦫꦢꦶꦂꦗ꧉
-ꦲꦶꦁꦩꦡꦫꦩ꧀ꦢꦸꦏ꧀ꦫꦸꦩꦸꦲꦸꦤ꧀​ꦠꦼꦊꦁꦔꦶꦁ​ꦏꦫꦡꦺꦴꦤ꧀ꦗꦮꦶ꧈
-ꦮꦼꦝꦶ​ꦒꦩ꧀ꦥꦶꦁ​ꦏꦗꦼꦁ​ꦭꦤ꧀ꦱꦤ꧀ꦤꦺꦱ꧀ꦱꦤ꧀ꦤꦺꦱ꧀ꦱꦶꦥꦸꦤ꧀​
-ꦩꦺꦴꦁꦏ​ꦱꦫꦮꦺꦢꦶꦤꦶꦁꦫꦠ꧀​ꦢꦺꦫꦤꦿꦸꦱ꧀ꦏꦼꦤ꧀ꦲꦸꦗ꧀ꦮꦭꦤ꧀ꦤꦶꦁ꧈
-ꦩꦶꦤꦺꦴꦁꦏ​ꦮꦏꦶꦭ꧀ꦪꦪꦱꦤ꧀ꦏꦭ꧀ꦭꦺꦴꦲꦸꦱ꧀ꦠꦼ​ꦒꦸꦭ꧀ꦧꦺꦤꦏꦶꦲꦤ꧀꧇
-ꦥꦶꦤꦽꦤꦃꦏꦼꦤ꧀ꦩꦁꦒꦺꦤ꧀ꦤꦶꦥꦸꦤ꧀​ꦲꦶꦁ​ꦥꦥꦤ꧀ꦲꦶꦁꦏꦁ​ꦥꦏꦺꦴꦭꦶꦃ꧈
-ꦠꦸꦩꦸꦗ꧀ꦮꦺꦁ​ꦊꦉꦱ꧀ꦤꦼꦂꦫꦶꦥꦸꦤ꧀​ꦱꦸꦱꦠꦾ​ꦠꦼꦩꦼꦤ꧀ꦤꦸꦲꦺꦴꦤ꧀ꦤꦶ꧈
-ꦲꦶꦁꦏꦁ​ꦲꦔꦽꦁꦒꦤ꧀ꦤꦶ​ꦑꦫꦡꦺꦴꦤ꧀ꦢꦊꦩ꧀ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ​ꦲꦢꦶꦟꦶꦁꦔꦿꦠ꧀꧈
-ꦗꦸꦩꦼꦤꦼꦁ​ꦢꦊꦩ꧀ꦟꦡ​ꦲꦩꦉꦁꦔꦶ​ꦢꦶꦤ꧀ꦠꦼꦤ꧀ꦱꦼꦤꦺꦤ꧀ꦥꦺꦴꦤ꧀​ꦠꦁꦒꦭ꧀ꦏꦥꦶꦁ꧇
-꧋ꦱꦧꦼꦤ꧀ꦲꦸꦮꦺꦴꦁꦏꦭꦲꦶꦫꦏꦺꦏꦤ꧀ꦛꦶꦩꦂꦢꦶꦏꦭꦤ꧀ꦢꦂꦧꦺꦩꦂꦠꦧꦠ꧀ꦭꦤ꧀ꦲꦏ꧀ꦲꦏ꧀ꦏꦁꦥꦝ꧉
-ꦱꦁꦏꦶꦁ​ꦥꦫ​ꦧꦺꦴꦁꦱ​ꦡꦾꦺꦴꦁꦲ꧀ꦮ​ꦒꦺꦴꦭꦺꦴꦁꦔꦤ꧀ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ​ꦲꦢꦶꦤꦶꦁꦔꦿꦠ꧀
-ꦔꦂꦰ​ꦢꦊꦩ꧀​ꦯꦩ꧀ꦦꦺꦪꦤ꧀ꦢꦊꦩ꧀​ꦲꦶꦁꦑꦁ​ꦯꦶꦟꦸꦮꦸꦤ꧀ꦏꦗꦼꦁ​ꦯꦸꦭ꧀ꦡꦤ꧀​ꦲꦩꦼꦁꦑꦸꦨꦸꦮꦟ꧈
-ꦲꦢꦼꦒ꧀ꦒꦶꦁ​ꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀​ꦪꦱꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦫꦢꦺꦤ꧀ꦔꦤ꧀ꦠꦺꦤ꧀ꦡꦸꦩꦼꦁꦒꦸꦁ​ꦦꦿꦮꦶꦫꦢꦶꦂꦗ꧈
-ꦒꦸꦧꦼꦂꦤꦸꦂ​ꦝꦃꦲꦺꦫꦃ​ꦆꦱ꧀ꦠꦶꦩꦺꦮꦃ​ꦪꦺꦴꦒꦾꦏꦂꦠ​ꦠꦸꦮꦶꦤ꧀ꦲꦶꦁꦏꦁ​ꦩꦶꦤꦸꦭ꧀ꦪ​ꦠꦸꦮꦤ꧀ꦪꦺꦴꦱꦺ​ꦧ꧀ꦭꦤ꧀ꦕꦺꦴ꧈
-ꦲꦶꦁꦒꦶꦃ​ꦥꦸꦤꦶꦏ​ꦧꦧ꧀ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀ꦠꦤꦃ​ꦔꦿꦶꦏꦶ​ꦲꦶꦁꦏꦁ​ꦱꦩꦶ​ꦔ꧀ꦭꦸꦫꦸꦒ꧀ꦝꦠꦼꦁ​ꦌꦫꦺꦴꦦꦃ꧈
-ꦱꦺꦴꦏꦺꦴꦁꦔꦤ꧀ꦱꦏꦶꦁ​ꦥꦫ​ꦩꦸꦱ꧀ꦭꦶꦩꦶꦤ꧀​ꦢꦺꦤ꧀ꦤꦺ​ꦲꦶꦁꦏꦁ​ꦔꦿꦚ꧀ꦕꦁ​ꦱꦲ​ꦔꦮꦠ꧀ꦲꦮꦠ꧀ꦠꦶ​ꦥꦁꦒꦫꦥ꧀ꦥꦶꦥꦸꦤ꧀ꦩꦱ꧀ꦗꦶꦢ꧀​ꦫꦢꦺꦤ꧀ꦔꦧꦺꦲꦶ​ꦕꦺꦴꦤ꧀ꦢꦿꦢꦶꦥꦿꦗ꧈
-ꦭꦗꦼꦁ​ꦏꦮꦏꦥ꧀ꦥꦏꦼꦤ꧀ꦏꦁꦒꦺ​ꦥꦂꦭꦸꦤꦶꦁ​ꦆꦱ꧀ꦭꦩ꧀ꦭꦤ꧀ꦩꦸꦱ꧀ꦭꦶꦩꦶꦤ꧀ꦲꦶꦁ​ꦱꦭꦩꦶꦭꦩꦶꦤꦶꦥꦸꦤ꧀​ꦥꦩ꧀ꦧꦶꦏꦏ꧀ꦏꦶꦥꦸꦤ꧀ꦲꦶꦁ​ꦢꦶꦤ꧀ꦠꦼꦤ꧀ꦏꦼꦩꦶꦱ꧀ꦏꦭꦶꦮꦺꦴꦤ꧀ꦠꦁꦒꦭ꧀ꦏꦥꦶꦁ꧇
-ꦲꦶꦁ​ꦔꦿꦶꦏꦶ​ꦔꦼꦕꦿꦠ꧀ꦒꦩ꧀ꦧꦂꦫꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦱꦮꦸꦁ​ꦮꦲꦸ​ꦤꦭꦶꦏ​ꦤꦸꦗꦸ​ꦠꦤ꧀ꦝꦶꦁꦔꦤ꧀ꦏꦭꦶꦪꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀ꦱꦏꦶꦁ​ꦲꦺꦴꦁꦓꦫꦶꦪꦼ​ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦲꦶꦁ​ꦲꦭꦸꦤ꧀ꦲꦭꦸꦤ꧀꧇
-ꦱꦢꦺꦫꦺꦁꦔꦶꦥꦸꦤ꧀ꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀ꦏꦒꦫꦥ꧀​ꦱꦩ꧀ꦥꦸꦤ꧀ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦩꦲꦸꦗꦸꦢ꧀ꦥꦤ꧀ꦝꦼꦩꦺꦤ꧀ꦤꦶꦁ​ꦩꦱ꧀ꦗꦶꦢ꧀​ꦯꦸꦫꦩ꧀ꦧꦶ​ꦱꦲ​ꦥꦭꦩ꧀ꦥꦃꦲꦤ꧀​ꦱꦂꦠ​ꦧꦺꦴꦤ꧀ꦝꦱꦮꦠꦮꦶꦱ꧀​ꦏꦢꦺꦴꦱ꧀ꦠ꧇
-ꦩꦸꦭ꧀ꦪꦏ꧀ꦏꦏꦺ​ꦈꦩ꧀ꦧꦸꦭ꧀ꦧꦶꦤꦁꦔꦸꦤ꧀ꦠꦩ꧀ꦩꦤ꧀ꦱꦂꦫꦶ​ꦏꦊꦏ꧀ꦱꦤ꧀ꦤꦏ꧀ꦏꦏꦼꦤ꧀ꦏꦤ꧀ꦛꦶ​ꦥꦚꦼꦁꦏꦸꦪꦸꦁꦔꦶꦥꦸꦤ꧀ꦪꦪꦱ꧀ꦱꦤ꧀ꦏꦭ꧀ꦭꦲꦸꦱ꧀ꦠꦼ​ꦒꦸꦭ꧀ꦧꦼꦤ꧀ꦏꦶꦲꦤ꧀ꦱꦲ​ꦏꦂꦉꦱ꧀ꦩꦺꦏ꧀ꦏꦏꦼꦤ꧀ꦢꦶꦤꦶꦁ​ꦲꦶꦁꦏꦁ​ꦩꦶꦤꦸꦭ꧀ꦪ​ꦯꦿꦶ​ꦯꦸꦭ꧀ꦠꦤ꧀ꦲꦩꦁꦏꦸꦨꦸꦮꦤ꧇
-ꦠꦸꦮꦤ꧀Dr꧇ꦯꦶꦩ꧀​ꦏꦶꦄꦌ
-ꦠꦸꦮꦤ꧀Ir꧇ꦭꦶꦩ꧀​ꦆꦁꦲ꧀ꦮꦶ
diff --git a/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt b/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt
deleted file mode 100644
index 550329833..000000000
--- a/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-𑂍 𑂎 𑂍𑂹𑂎 𑂍𑂹𑂎𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱 𑂍𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱𑂁 𑂍𑂹𑂎𑂹𑂎𑂱𑂀 𑂎𑂱𑂁
-𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
-𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
-𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
-𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
-𑂩𑂍 𑂩𑂹𑂍𑂱 𑂩𑂹𑂍𑂹𑂍𑂱 𑂩𑂹𑂍𑂹𑂍𑂵 𑂩𑂹𑂔𑂹𑂍𑂹𑂍𑂱 𑂩𑂹𑂞
diff --git a/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt b/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt
deleted file mode 100644
index 5a563c170..000000000
--- a/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-𐨤𐨪𐨌𐨪𐨿𐨗𐨸𐨅𐨌𐨏
-𐨀𐨁
-𐨐𐨁
-𐨠𐨁
-𐨀𐨂
-𐨱𐨂
-𐨨𐨂
-𐨀𐨃
-𐨨𐨃
-𐨀𐨅
-𐨐𐨅
-𐨠𐨅
-𐨡𐨅
-𐨀𐨆
-𐨤𐨆
-𐨨𐨌
-𐨯𐨍
-𐨀𐨎
-𐨐𐨏
-𐨗𐨸
-𐨒𐨹
-𐨨𐨺
-𐨢𐨁𐨐𐨿
-𐨐𐨿𐨮
-𐨨𐨿𐨪
-𐨬𐨿𐨱
-𐨯𐨿𐨟
-𐨯𐨿𐨩
-𐨪𐨿𐨟
-𐨟𐨿𐨪
-𐨫𐨿𐨤
-𐨤𐨿𐨫
-𐨐𐨿𐨫
-𐨟𐨿𐨬
-𐨐𐨿𐨟
-𐨑𐨿𐨐𐨿𐨮
diff --git a/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt
deleted file mode 100644
index 62e93176c..000000000
--- a/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ᨠ᩠ᨠᩮᩕ
-ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
diff --git a/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt
deleted file mode 100644
index faee30208..000000000
--- a/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-ᨣᩕ᩵ᩣᩴᨣᩕ᩠ᩅᩁ
-ᨣᩕ᩵ᩮ᩠ᨦᨣᩕᩢ᩠ᨯ
-ᩅᩥᨣᩅᩰᩬᩡ
-ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
-ᨶᩫᨶ᩠ᨲᩕᩧ
-ᩈ᩠ᨾ᩵ᩣᩴᩈ᩠ᨾᩮᩬᩥ
-ᩀᩢ᩠᩵ᨦᨶ᩶ᩣᩴ
-ᩉᩫ᩠ᨯᩉ᩠ᨿᩬᩴ᩶
-ᩅᩥᨱ᩠ᨬᩣ᩠ᨱ
-ᨠᩕᩫ᩠ᨮᩉᩫ᩠ᩅᨷᩫ᩠ᩅ
-ᨷᩴ᩠᩵ᨯᩲ᩶
-ᨷᩴ᩠᩶ᨯᩲ᩵
-ᨺᩮᩥᩢ᩠ᨠ
-ᨡᩧ᩠᩶ᨦ᩻
-ᨸᩢ᩠᩶ᨶ
-ᨵᩥᩢ᩠᩶ᨶ
-ᨷᩣ᩠ᨦ
-ᨷᩤ᩠ᨦ
-ᨻᩮᩬᩧ᩵ᩋᩉᩲ᩶
-ᨾᩨᨤᩕᩢ᩠᩵ᨦ
-ᨴᩣᩴᩋᩁᩲ
-ᩈᩢᨬ᩠ᨬᩣ
-◌ᩲ
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index a69005ab9..e6d2325ee 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -7,6 +7,8 @@ SUBDIRS = repack_tests
EXTRA_DIST += \
$(TESTS) \
+ $(DISABLED_TESTS) \
+ expected/32bit_var_store \
expected/basics \
expected/full-font \
expected/glyf_bug_3131 \
@@ -33,22 +35,31 @@ EXTRA_DIST += \
expected/layout.gdef \
expected/layout.gdef.glyphset \
expected/layout.context \
+ expected/layout.context_format2 \
expected/layout.gdef-varstore \
expected/layout.gdef-attachlist \
expected/layout.notonastaliqurdu \
expected/layout.tinos \
expected/layout.duplicate_features \
expected/layout.unsorted_featurelist \
+ expected/layout.drop_feature \
expected/cmap \
expected/cmap14 \
expected/sbix \
expected/colr \
+ expected/colr_glyphs \
expected/colrv1 \
expected/colr_with_components \
expected/cbdt \
expected/variable \
expected/glyph_names \
expected/math \
+ expected/math_coverage_offset \
+ expected/post \
+ expected/full_instance \
+ expected/instance_feature_variations \
+ expected/instantiate_glyf \
+ expected/pin_all_at_default \
fonts \
profiles \
$(NULL)
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index c1a70ba90..845a77e73 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -1,4 +1,5 @@
TESTS = \
+ tests/32bit_var_store.tests \
tests/basics.tests \
tests/cbdt.tests \
tests/cff-full-font.tests \
@@ -7,12 +8,14 @@ TESTS = \
tests/cmap.tests \
tests/cmap14.tests \
tests/colr.tests \
+ tests/colr_glyphs.tests \
tests/colrv1.tests \
tests/colr_with_components.tests \
tests/full-font.tests \
tests/glyf_bug_3131.tests \
tests/japanese.tests \
tests/layout.context.tests \
+ tests/layout.context_format2.tests \
tests/layout.gdef-attachlist.tests \
tests/layout.gdef-varstore.tests \
tests/layout.gdef.tests \
@@ -37,10 +40,17 @@ TESTS = \
tests/layout.tinos.tests \
tests/layout.duplicate_features.tests \
tests/layout.unsorted_featurelist.tests \
- tests/sbix.tests \
+ tests/layout.drop_feature.tests \
+ tests/sbix.tests \
tests/variable.tests \
tests/glyph_names.tests \
tests/math.tests \
+ tests/math_coverage_offset.tests \
+ tests/post.tests \
+ tests/full_instance.tests \
+ tests/instance_feature_variations.tests \
+ tests/instantiate_glyf.tests \
+ tests/pin_all_at_default.tests \
$(NULL)
# TODO: re-enable once colrv1 subsetting is stabilized.
@@ -51,5 +61,6 @@ TESTS = \
XFAIL_TESTS = \
$(NULL)
+# Disabled because instancing is only available w/ experimental API on.
DISABLED_TESTS = \
$(NULL)
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
new file mode 100644
index 000000000..6b28104bc
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
new file mode 100644
index 000000000..42a573ee6
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
new file mode 100644
index 000000000..50f196505
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
new file mode 100644
index 000000000..77dbebe03
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
new file mode 100644
index 000000000..e2d18184d
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
new file mode 100644
index 000000000..bc42c2683
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
new file mode 100644
index 000000000..7a3481d64
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
new file mode 100644
index 000000000..4fb8b80bf
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
new file mode 100644
index 000000000..6b28104bc
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
new file mode 100644
index 000000000..42a573ee6
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
new file mode 100644
index 000000000..4b6ad6fb1
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
new file mode 100644
index 000000000..c861f6552
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
new file mode 100644
index 000000000..e2d18184d
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
new file mode 100644
index 000000000..bfecc0c11
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
new file mode 100644
index 000000000..d742e5492
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
Binary files differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
new file mode 100644
index 000000000..69e32ea6c
--- /dev/null
+++ b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
index f80bdd486..749ef45e7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
index 37ea7b876..8a7e8281c 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
index 7e548912a..711c070aa 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
index f80bdd486..749ef45e7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
index d27fcd425..56cba1bd0 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
index 0d79f43bf..e2fe5f956 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
index 686180c1c..509ba2aae 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
index c09fca40d..660c052bf 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
index f80bdd486..749ef45e7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
index f80bdd486..749ef45e7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
index f80bdd486..749ef45e7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
index cac5bbd56..e33f66c27 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
index 441646ad1..93aa9829b 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.default.41.ttf b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.default.41.ttf
new file mode 100644
index 000000000..0c9c42f84
--- /dev/null
+++ b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.default.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints-retain-gids.41.ttf b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints-retain-gids.41.ttf
new file mode 100644
index 000000000..d676e52cd
--- /dev/null
+++ b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints-retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints.41.ttf b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints.41.ttf
new file mode 100644
index 000000000..96c0396a3
--- /dev/null
+++ b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.drop-hints.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.retain-gids.41.ttf b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.retain-gids.41.ttf
new file mode 100644
index 000000000..d15499ede
--- /dev/null
+++ b/test/subset/data/expected/colr_glyphs/BungeeColor-Regular.retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
index 67020e24d..8c93da9ff 100644
--- a/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
+++ b/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
index a2be48415..6857f7be7 100644
--- a/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
+++ b/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
index 67020e24d..8c93da9ff 100644
--- a/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
+++ b/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
index a2be48415..6857f7be7 100644
--- a/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
+++ b/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..b66269f07
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..4d506845d
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..38de0fe28
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..2de0e2cd7
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..cd3d30aa3
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
new file mode 100644
index 000000000..3c04b26d8
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..d7d7a736a
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..9dbd4986b
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
new file mode 100644
index 000000000..836df1cc1
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..263c6447a
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..6fed6741a
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..e6dd264da
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
new file mode 100644
index 000000000..5ecaaed80
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..69d7875bc
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..5f46234ae
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..424209a66
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
new file mode 100644
index 000000000..5397c5b9c
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..8660d677e
--- /dev/null
+++ b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..57ff1f9e2
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
index 930d87133..b0069ab75 100644
--- a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..57ff1f9e2
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..d45039738
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..d7dbd7543
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..f86d3dd21
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
new file mode 100644
index 000000000..03a14d05f
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..cac2b1e84
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..715c714e2
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
new file mode 100644
index 000000000..7d9ca258a
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..b402ea9b0
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..40fb67a99
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..28c360518
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
new file mode 100644
index 000000000..590ccb972
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..bbab9cad9
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644
index 000000000..08bdd8383
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644
index 000000000..baa346835
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
new file mode 100644
index 000000000..06dfe7442
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 000000000..c278d1fd7
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
new file mode 100644
index 000000000..ca2aeeff6
--- /dev/null
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
new file mode 100644
index 000000000..04be94efe
--- /dev/null
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf
new file mode 100644
index 000000000..ca2aeeff6
--- /dev/null
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf
Binary files differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf
new file mode 100644
index 000000000..04be94efe
--- /dev/null
+++ b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
index d45c85611..d2a2db9ff 100644
--- a/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.retain-all-codepoint.wght=400.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.retain-all-codepoint.wght=400.ttf
new file mode 100644
index 000000000..6a76402e7
--- /dev/null
+++ b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.retain-all-codepoint.wght=400.ttf
Binary files differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.notdef-outline.retain-all-codepoint.wght=400.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.notdef-outline.retain-all-codepoint.wght=400.ttf
new file mode 100644
index 000000000..3214a7781
--- /dev/null
+++ b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.notdef-outline.retain-all-codepoint.wght=400.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf
new file mode 100644
index 000000000..fee5f9d4d
--- /dev/null
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf
new file mode 100644
index 000000000..2b44f1fe0
--- /dev/null
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf
new file mode 100644
index 000000000..060f73568
--- /dev/null
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf
Binary files differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf
new file mode 100644
index 000000000..9ed86290b
--- /dev/null
+++ b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
index 70dd0fdc6..5ae5d5b20 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
index f9349f6f3..cfe6648e2 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
index 07e6ad538..0e98d1a93 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
index 070f9ec0d..6530ab6ec 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
index 60fd45c69..cac1abba3 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
index 07e6ad538..0e98d1a93 100644
--- a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 000000000..c2ef8fed6
--- /dev/null
+++ b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf
new file mode 100644
index 000000000..c2ef8fed6
--- /dev/null
+++ b/test/subset/data/expected/layout.context_format2/NotoSansNewa-Regular.layout-test.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf
new file mode 100644
index 000000000..7dcb3ecec
--- /dev/null
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 000000000..f17c60961
--- /dev/null
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 000000000..490ab70c7
--- /dev/null
+++ b/test/subset/data/expected/layout.drop_feature/SpectralSC-ExtraLightItalic.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
index cdd6bc7ba..c59062184 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
index 0de5e9850..97948b08f 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
index cdd6bc7ba..c59062184 100644
--- a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
index ab0c1d1c6..c64ef972a 100644
--- a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
index 2306381ea..b4a267702 100644
--- a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
index ab0c1d1c6..c64ef972a 100644
--- a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
index 7f9a3b182..615474b3b 100644
--- a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
index 148b31812..47ae513d0 100644
--- a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
index 80a1439f9..240cb05a2 100644
--- a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
index 1d3f3cd70..f6b78bc97 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
index 5a0d0c4aa..6f2e7ef13 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
index b3d6ae9e4..ff0595a94 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
index 0a693c641..808605142 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
index 128c1d413..0a26e0fd1 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
index b3d6ae9e4..ff0595a94 100644
--- a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf
index e6c8b6fa9..8d5bdcf9d 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf
index bf2ff01fa..5fbab258a 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf
index 1c0f0e932..ad9c49772 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf
index 9424060c4..88271273c 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,6D2.ttf
new file mode 100644
index 000000000..39f534db5
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf
index fdd0b84ad..0f992dca2 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
new file mode 100644
index 000000000..a49c63e0c
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf
index 658093782..440b786ea 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf
index 64d8565d7..d31f8846f 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf
index cb2e429c4..33ef61fab 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf
index be237a782..eb473b410 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,6D2.ttf
new file mode 100644
index 000000000..ff3a8168d
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf
index d69ba9996..57470a752 100644
--- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 000000000..a49c63e0c
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 000000000..7d58b3c63
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
new file mode 100644
index 000000000..e402e57bb
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf
new file mode 100644
index 000000000..17ad7cd05
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf
new file mode 100644
index 000000000..29166f75a
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
new file mode 100644
index 000000000..5683d04b2
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
new file mode 100644
index 000000000..e19feda42
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 000000000..ea153c9f5
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 000000000..4df2620e2
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
new file mode 100644
index 000000000..fb9746e01
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf
new file mode 100644
index 000000000..1ef5e8dae
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf
new file mode 100644
index 000000000..5e2dee1d6
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
new file mode 100644
index 000000000..81319fdc8
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
new file mode 100644
index 000000000..b9aa70b85
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 000000000..4458d5fbf
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
index 5e7157d49..b1c576925 100644
--- a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
index e7b13f27a..9b703f421 100644
--- a/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
index 5e7157d49..b1c576925 100644
--- a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
index 401187caa..edf54a3d6 100644
--- a/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
index 376ecc8a6..8bf70edec 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
index b299db741..770b359ff 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
index f3f6f4aee..c7e0040b9 100644
--- a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
index 3c2434dd3..a17ff4108 100644
--- a/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
index 7ff30bbd9..ca9aa2562 100644
--- a/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
index db3f9a10d..15d34966a 100644
--- a/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
index cce064f81..d7ee94a3a 100644
--- a/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 000000000..0df9dca60
--- /dev/null
+++ b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 000000000..6686d486b
--- /dev/null
+++ b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf
new file mode 100644
index 000000000..0df9dca60
--- /dev/null
+++ b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.keep-all-layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 000000000..1ce1535e5
--- /dev/null
+++ b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 000000000..f46479b26
--- /dev/null
+++ b/test/subset/data/expected/math_coverage_offset/Caudex-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
new file mode 100644
index 000000000..1523a99f9
--- /dev/null
+++ b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
Binary files differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf
new file mode 100644
index 000000000..1523a99f9
--- /dev/null
+++ b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.c30,c36,c40,c4d.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.c30,c36,c40,c4d.ttf
new file mode 100644
index 000000000..89bbc9912
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.c30,c36,c40,c4d.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 000000000..6d4ea7720
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.c30,c36,c40,c4d.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.c30,c36,c40,c4d.ttf
new file mode 100644
index 000000000..48ca1c53e
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.c30,c36,c40,c4d.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 000000000..d96dd3614
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.c30,c36,c40,c4d.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.c30,c36,c40,c4d.ttf
new file mode 100644
index 000000000..ae3f65964
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.c30,c36,c40,c4d.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 000000000..3163b3caf
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.c30,c36,c40,c4d.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.c30,c36,c40,c4d.ttf
new file mode 100644
index 000000000..7b154997a
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.c30,c36,c40,c4d.ttf
Binary files differ
diff --git a/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 000000000..3927219b8
--- /dev/null
+++ b/test/subset/data/expected/post/SreeKrushnadevaraya-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/fonts/32bit_var_store.otf b/test/subset/data/fonts/32bit_var_store.otf
new file mode 100644
index 000000000..1d376c932
--- /dev/null
+++ b/test/subset/data/fonts/32bit_var_store.otf
Binary files differ
diff --git a/test/subset/data/fonts/BungeeColor-Regular.ttf b/test/subset/data/fonts/BungeeColor-Regular.ttf
new file mode 100644
index 000000000..d8eabb3b6
--- /dev/null
+++ b/test/subset/data/fonts/BungeeColor-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Caudex-Regular.ttf b/test/subset/data/fonts/Caudex-Regular.ttf
new file mode 100644
index 000000000..669f9f8c9
--- /dev/null
+++ b/test/subset/data/fonts/Caudex-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/MPLUS1-Variable.ttf b/test/subset/data/fonts/MPLUS1-Variable.ttf
new file mode 100644
index 000000000..078795d27
--- /dev/null
+++ b/test/subset/data/fonts/MPLUS1-Variable.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf
index d05dabe0b..ef4c60f81 100644
--- a/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf
+++ b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf b/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf
index 1437c343e..205192c81 100644
--- a/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf
+++ b/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf
Binary files differ
diff --git a/perf/fonts/NotoSansDevanagari-Regular.ttf b/test/subset/data/fonts/NotoSansDevanagari-Regular.ttf
index a9884a538..a9884a538 100644
--- a/perf/fonts/NotoSansDevanagari-Regular.ttf
+++ b/test/subset/data/fonts/NotoSansDevanagari-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoSansNewa-Regular.ttf b/test/subset/data/fonts/NotoSansNewa-Regular.ttf
new file mode 100644
index 000000000..b79b9cb00
--- /dev/null
+++ b/test/subset/data/fonts/NotoSansNewa-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Roboto-Variable.ABC.ttf b/test/subset/data/fonts/Roboto-Variable.ABC.ttf
new file mode 100644
index 000000000..6cf001fc8
--- /dev/null
+++ b/test/subset/data/fonts/Roboto-Variable.ABC.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Roboto-Variable.composite.ttf b/test/subset/data/fonts/Roboto-Variable.composite.ttf
new file mode 100644
index 000000000..d0e12c0cc
--- /dev/null
+++ b/test/subset/data/fonts/Roboto-Variable.composite.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Roboto-Variable.ttf b/test/subset/data/fonts/Roboto-Variable.ttf
new file mode 100644
index 000000000..175c7b7e6
--- /dev/null
+++ b/test/subset/data/fonts/Roboto-Variable.ttf
Binary files differ
diff --git a/test/subset/data/fonts/RobotoFlex-Variable.ttf b/test/subset/data/fonts/RobotoFlex-Variable.ttf
new file mode 100644
index 000000000..bd32e0d75
--- /dev/null
+++ b/test/subset/data/fonts/RobotoFlex-Variable.ttf
Binary files differ
diff --git a/test/subset/data/fonts/SpectralSC-ExtraLightItalic.ttf b/test/subset/data/fonts/SpectralSC-ExtraLightItalic.ttf
new file mode 100644
index 000000000..e5b0f4798
--- /dev/null
+++ b/test/subset/data/fonts/SpectralSC-ExtraLightItalic.ttf
Binary files differ
diff --git a/test/subset/data/fonts/SreeKrushnadevaraya-Regular.ttf b/test/subset/data/fonts/SreeKrushnadevaraya-Regular.ttf
new file mode 100644
index 000000000..46207921b
--- /dev/null
+++ b/test/subset/data/fonts/SreeKrushnadevaraya-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/colr-table.ttf b/test/subset/data/fonts/colr-table.ttf
index c4b2a55a5..d930faae9 100644
--- a/test/subset/data/fonts/colr-table.ttf
+++ b/test/subset/data/fonts/colr-table.ttf
Binary files differ
diff --git a/test/subset/data/profiles/filter-scripts-features.2.txt b/test/subset/data/profiles/filter-scripts-features.2.txt
new file mode 100644
index 000000000..6890a27c6
--- /dev/null
+++ b/test/subset/data/profiles/filter-scripts-features.2.txt
@@ -0,0 +1,2 @@
+--layout-scripts=grek,latn
+--layout-features=liga
diff --git a/test/subset/data/profiles/filter-scripts-features.txt b/test/subset/data/profiles/filter-scripts-features.txt
new file mode 100644
index 000000000..971824c47
--- /dev/null
+++ b/test/subset/data/profiles/filter-scripts-features.txt
@@ -0,0 +1,2 @@
+--layout-scripts=grek,cyrl
+--layout-features=numr,onum
diff --git a/test/subset/data/profiles/filter-scripts.txt b/test/subset/data/profiles/filter-scripts.txt
new file mode 100644
index 000000000..428f7fabf
--- /dev/null
+++ b/test/subset/data/profiles/filter-scripts.txt
@@ -0,0 +1 @@
+--layout-scripts=grek,cyrl
diff --git a/test/subset/data/profiles/no-scripts.txt b/test/subset/data/profiles/no-scripts.txt
new file mode 100644
index 000000000..9bbc847ff
--- /dev/null
+++ b/test/subset/data/profiles/no-scripts.txt
@@ -0,0 +1 @@
+--layout-scripts-=*
diff --git a/test/subset/data/tests/32bit_var_store.tests b/test/subset/data/tests/32bit_var_store.tests
new file mode 100644
index 000000000..015549e29
--- /dev/null
+++ b/test/subset/data/tests/32bit_var_store.tests
@@ -0,0 +1,16 @@
+FONTS:
+32bit_var_store.otf
+
+PROFILES:
+notdef-outline.txt
+notdef-outline-retain-gids.txt
+
+SUBSETS:
+a
+b
+c
+d
+ab
+ac
+ad
+abcd
diff --git a/test/subset/data/tests/colr_glyphs.tests b/test/subset/data/tests/colr_glyphs.tests
new file mode 100644
index 000000000..005b55005
--- /dev/null
+++ b/test/subset/data/tests/colr_glyphs.tests
@@ -0,0 +1,11 @@
+FONTS:
+BungeeColor-Regular.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+A
diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests
index d9519b69f..31cb92c5d 100644
--- a/test/subset/data/tests/full-font.tests
+++ b/test/subset/data/tests/full-font.tests
@@ -5,8 +5,13 @@ SourceSerifVariable-Roman.ttf
PROFILES:
default.txt
drop-hints.txt
+no-scripts.txt
+filter-scripts.txt
+filter-scripts-features.txt
+filter-scripts-features.2.txt
SUBSETS:
abc
Ǽ!A bc
+abcdefghijk
×ØÙÚÞ
diff --git a/test/subset/data/tests/full_instance.tests b/test/subset/data/tests/full_instance.tests
new file mode 100644
index 000000000..f99e5ebe9
--- /dev/null
+++ b/test/subset/data/tests/full_instance.tests
@@ -0,0 +1,13 @@
+FONTS:
+Roboto-Variable.ttf
+
+PROFILES:
+default.txt
+no-prune-unicode-ranges.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=150,wdth=80
+wght=300,wdth=90
diff --git a/test/subset/data/tests/instance_feature_variations.tests b/test/subset/data/tests/instance_feature_variations.tests
new file mode 100644
index 000000000..4166b13ca
--- /dev/null
+++ b/test/subset/data/tests/instance_feature_variations.tests
@@ -0,0 +1,12 @@
+FONTS:
+MPLUS1-Variable.ttf
+
+PROFILES:
+default.txt
+notdef-outline.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=400
diff --git a/test/subset/data/tests/instantiate_glyf.tests b/test/subset/data/tests/instantiate_glyf.tests
new file mode 100644
index 000000000..e297667ad
--- /dev/null
+++ b/test/subset/data/tests/instantiate_glyf.tests
@@ -0,0 +1,13 @@
+FONTS:
+Roboto-Variable.ABC.ttf
+Roboto-Variable.composite.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=650,wdth=85
+wght=200,wdth=90
diff --git a/test/subset/data/tests/layout.context_format2.tests b/test/subset/data/tests/layout.context_format2.tests
new file mode 100644
index 000000000..019fb94dc
--- /dev/null
+++ b/test/subset/data/tests/layout.context_format2.tests
@@ -0,0 +1,9 @@
+FONTS:
+NotoSansNewa-Regular.ttf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+*
diff --git a/test/subset/data/tests/layout.drop_feature.tests b/test/subset/data/tests/layout.drop_feature.tests
new file mode 100644
index 000000000..9d15ce27b
--- /dev/null
+++ b/test/subset/data/tests/layout.drop_feature.tests
@@ -0,0 +1,10 @@
+FONTS:
+SpectralSC-ExtraLightItalic.ttf
+
+PROFILES:
+default.txt
+glyph-names.txt
+notdef-outline.txt
+
+SUBSETS:
+*
diff --git a/test/subset/data/tests/layout.notonastaliqurdu.tests b/test/subset/data/tests/layout.notonastaliqurdu.tests
index e305117bb..c298f54e1 100644
--- a/test/subset/data/tests/layout.notonastaliqurdu.tests
+++ b/test/subset/data/tests/layout.notonastaliqurdu.tests
@@ -1,5 +1,6 @@
FONTS:
NotoNastaliqUrdu-Bold.ttf
+NotoNastaliqUrdu-Regular.ttf
PROFILES:
default.txt
@@ -11,3 +12,5 @@ SUBSETS:
غير
سماء لا
الحب
+سے
+*
diff --git a/test/subset/data/tests/math_coverage_offset.tests b/test/subset/data/tests/math_coverage_offset.tests
new file mode 100644
index 000000000..ac333b7be
--- /dev/null
+++ b/test/subset/data/tests/math_coverage_offset.tests
@@ -0,0 +1,12 @@
+FONTS:
+Caudex-Regular.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+glyph-names.txt
+notdef-outline.txt
+keep-all-layout-features.txt
+
+SUBSETS:
+*
diff --git a/test/subset/data/tests/pin_all_at_default.tests b/test/subset/data/tests/pin_all_at_default.tests
new file mode 100644
index 000000000..068c8ad96
--- /dev/null
+++ b/test/subset/data/tests/pin_all_at_default.tests
@@ -0,0 +1,12 @@
+FONTS:
+Roboto-Variable.ABC.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=drop,wdth=100
+wght=400,wdth=100.0
diff --git a/test/subset/data/tests/post.tests b/test/subset/data/tests/post.tests
new file mode 100644
index 000000000..d6c6a357d
--- /dev/null
+++ b/test/subset/data/tests/post.tests
@@ -0,0 +1,12 @@
+FONTS:
+SreeKrushnadevaraya-Regular.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+glyph-names.txt
+notdef-outline.txt
+
+SUBSETS:
+U+c30,U+c36,U+c40,U+c4d
+*
diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 2182643ab..2b7a87f29 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -27,15 +27,30 @@ def strip_check_sum (ttx_string):
ttx_string, count=1)
-def generate_expected_output(input_file, unicodes, profile_flags, output_directory, font_name):
+def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, output_directory, font_name):
+ input_path = input_file
+ if instance_flags:
+ instance_path = os.path.join(tempfile.mkdtemp (), font_name)
+ args = ["fonttools", "varLib.instancer",
+ "--no-overlap-flag",
+ "--no-recalc-bounds",
+ "--no-recalc-timestamp",
+ "--output=%s" % instance_path,
+ input_file]
+ args.extend(instance_flags)
+ check_call(args)
+ input_path = instance_path
+
fonttools_path = os.path.join(tempfile.mkdtemp (), font_name)
- args = ["fonttools", "subset", input_file]
+ args = ["fonttools", "subset", input_path]
args.extend(["--drop-tables+=DSIG",
"--drop-tables-=sbix",
+ "--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself.
"--unicodes=%s" % unicodes,
"--output-file=%s" % fonttools_path])
args.extend(profile_flags)
check_call(args)
+
with io.StringIO () as fp:
with TTFont (fonttools_path) as font:
font.saveXML (fp)
@@ -50,7 +65,10 @@ def generate_expected_output(input_file, unicodes, profile_flags, output_directo
"--drop-tables+=DSIG",
"--drop-tables-=sbix"]
args.extend(profile_flags)
+ if instance_flags:
+ args.extend(["--instance=%s" % ','.join(instance_flags)])
check_call(args)
+
with io.StringIO () as fp:
with TTFont (harfbuzz_path) as font:
font.saveXML (fp)
@@ -84,4 +102,4 @@ for path in args:
font_name = test.get_font_name()
print("Creating subset %s/%s" % (output_directory, font_name))
generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
- output_directory, font_name)
+ test.get_instance_flags(), output_directory, font_name)
diff --git a/test/subset/meson.build b/test/subset/meson.build
index 729aa3bfc..77a2029d7 100644
--- a/test/subset/meson.build
+++ b/test/subset/meson.build
@@ -25,24 +25,34 @@ tests = [
'layout.gdef.glyphset',
'layout.khmer',
'layout.context',
+ 'layout.context_format2',
'layout.gdef-varstore',
'layout.gdef-attachlist',
'layout.notonastaliqurdu',
'layout.tinos',
'layout.duplicate_features',
'layout.unsorted_featurelist',
+ 'layout.drop_feature',
'cmap',
'cmap14',
'sbix',
'colr',
+ 'colr_glyphs',
'math',
-# TODO: re-enable once colrv1 subsetting is stabilized.
-# 'colrv1.notoemoji',
+ 'math_coverage_offset',
+ # TODO: re-enable once colrv1 subsetting is stabilized.
+ # 'colrv1.notoemoji',
'colrv1',
'colr_with_components',
'cbdt',
'variable',
'glyph_names',
+ 'post',
+ '32bit_var_store',
+ 'pin_all_at_default',
+ 'instantiate_glyf',
+ 'full_instance',
+ 'instance_feature_variations',
]
repack_tests = [
@@ -54,7 +64,6 @@ repack_tests = [
'space_splitting',
]
-
run_test = find_program('run-tests.py')
foreach t : tests
@@ -63,12 +72,12 @@ foreach t : tests
test(t, run_test,
args: [
hb_subset,
- join_paths(meson.current_source_dir(), 'data', 'tests', fname),
+ meson.current_source_dir() / 'data' / 'tests' / fname,
],
# as the tests are ran concurrently let's raise acceptable time here
# ideally better to break and let meson handles them in parallel
timeout: 500,
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
+ workdir: meson.current_build_dir() / '..' / '..',
suite: 'subset',
)
endforeach
@@ -81,9 +90,9 @@ foreach t : repack_tests
test(t, run_repack_test,
args: [
hb_subset,
- join_paths(meson.current_source_dir(), 'data', 'repack_tests', fname),
+ meson.current_source_dir() / 'data' / 'repack_tests' / fname,
],
- workdir: join_paths(meson.current_build_dir(), '..', '..'),
+ workdir: meson.current_build_dir() / '..' / '..',
suite: ['subset', 'repack'],
)
endforeach
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index 79830c452..db3c042a1 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -11,7 +11,6 @@ import sys
import tempfile
import shutil
import io
-import hashlib
from subset_test_suite import SubsetTestSuite
@@ -48,14 +47,19 @@ def fail_test (test, cli_args, message):
print (' expected_file %s' % os.path.abspath (expected_file))
return 1
-def run_test (test, should_check_ots):
+def run_test (test, should_check_ots, preprocess):
out_file = os.path.join (tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
cli_args = ["--font-file=" + test.font_path,
"--output-file=" + out_file,
"--unicodes=%s" % test.unicodes (),
"--drop-tables+=DSIG",
"--drop-tables-=sbix"]
+ if preprocess:
+ cli_args.extend(["--preprocess-face",])
+
cli_args.extend (test.get_profile_flags ())
+ if test.get_instance_flags ():
+ cli_args.extend (["--instance=%s" % ','.join(test.get_instance_flags ())])
ret = subset_cmd (cli_args)
if ret != "success":
@@ -63,11 +67,11 @@ def run_test (test, should_check_ots):
expected_file = os.path.join (test_suite.get_output_directory (), test.get_font_name ())
with open (expected_file, "rb") as fp:
- expected_hash = hashlib.sha224(fp.read()).hexdigest()
+ expected_contents = fp.read()
with open (out_file, "rb") as fp:
- actual_hash = hashlib.sha224(fp.read()).hexdigest()
+ actual_contents = fp.read()
- if expected_hash == actual_hash:
+ if expected_contents == actual_contents:
if should_check_ots:
print ("Checking output with ots-sanitize.")
if not check_ots (out_file):
@@ -140,7 +144,10 @@ for path in args:
print ("Running tests in " + path)
test_suite = SubsetTestSuite (path, f.read ())
for test in test_suite.tests ():
- fails += run_test (test, has_ots)
+ # Tests are run with and without preprocessing, results should be the
+ # same between them.
+ fails += run_test (test, has_ots, False)
+ fails += run_test (test, has_ots, True)
if fails != 0:
sys.exit ("%d test(s) failed." % fails)
diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py
index a58d01703..5ef4de303 100644
--- a/test/subset/subset_test_suite.py
+++ b/test/subset/subset_test_suite.py
@@ -5,10 +5,11 @@ import os
# A single test in a subset test suite. Identifies a font
# a subsetting profile, and a subset to be cut.
class Test:
- def __init__(self, font_path, profile_path, subset):
+ def __init__(self, font_path, profile_path, subset, instance):
self.font_path = font_path
self.profile_path = profile_path
self.subset = subset
+ self.instance = instance
def unicodes(self):
import re
@@ -20,23 +21,38 @@ class Test:
else:
return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
+ def instance_name(self):
+ if not self.instance:
+ return self.instance
+ else:
+ s = "." + self.instance.replace(':', '-')
+ return s
+
def get_profile_flags(self):
with open (self.profile_path, mode="r", encoding="utf-8") as f:
return f.read().splitlines()
+ def get_instance_flags(self):
+ if not self.instance:
+ return []
+ else:
+ return self.instance.split(',')
+
def get_font_name(self):
font_base_name = os.path.basename(self.font_path)
font_base_name_parts = os.path.splitext(font_base_name)
profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
if self.unicodes() == "*":
- return "%s.%s.retain-all-codepoint%s" % (font_base_name_parts[0],
+ return "%s.%s.retain-all-codepoint%s%s" % (font_base_name_parts[0],
profile_name,
+ self.instance_name(),
font_base_name_parts[1])
else:
- return "%s.%s.%s%s" % (font_base_name_parts[0],
+ return "%s.%s.%s%s%s" % (font_base_name_parts[0],
profile_name,
self.unicodes(),
+ self.instance_name(),
font_base_name_parts[1])
def get_font_extension(self):
@@ -53,6 +69,7 @@ class SubsetTestSuite:
self.fonts = []
self.profiles = []
self.subsets = []
+ self.instances = []
self._parse(definition)
def get_output_directory(self):
@@ -73,7 +90,11 @@ class SubsetTestSuite:
for profile in self.profiles:
profile = os.path.join(self._base_path(), "profiles", profile)
for subset in self.subsets:
- yield Test(font, profile, subset)
+ if self.instances:
+ for instance in self.instances:
+ yield Test(font, profile, subset, instance)
+ else:
+ yield Test(font, profile, subset, "")
def _base_path(self):
return os.path.dirname(os.path.dirname(self.test_path))
@@ -82,7 +103,8 @@ class SubsetTestSuite:
destinations = {
"FONTS:": self.fonts,
"PROFILES:": self.profiles,
- "SUBSETS:": self.subsets
+ "SUBSETS:": self.subsets,
+ "INSTANCES:": self.instances
}
current_destination = None
diff --git a/test/threads/Makefile.am b/test/threads/Makefile.am
new file mode 100644
index 000000000..f0347d492
--- /dev/null
+++ b/test/threads/Makefile.am
@@ -0,0 +1,17 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+SUBDIRS =
+
+EXTRA_DIST += \
+ meson.build \
+ hb-shape-threads.cc \
+ hb-subset-threads.cc \
+ $(NULL)
+
+# Convenience targets:
+lib:
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
diff --git a/test/threads/hb-shape-threads.cc b/test/threads/hb-shape-threads.cc
new file mode 100644
index 000000000..96dff3441
--- /dev/null
+++ b/test/threads/hb-shape-threads.cc
@@ -0,0 +1,210 @@
+#include <cassert>
+#include <cstring>
+#include <thread>
+#include <condition_variable>
+#include <vector>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+ const char *font_path;
+ const char *text_path;
+ bool is_variable;
+} default_tests[] =
+{
+
+ {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+ "perf/texts/fa-thelittleprince.txt",
+ false},
+
+ {"perf/fonts/Amiri-Regular.ttf",
+ "perf/texts/fa-thelittleprince.txt",
+ false},
+
+ {"perf/fonts/Roboto-Regular.ttf",
+ "perf/texts/en-thelittleprince.txt",
+ false},
+
+ {"perf/fonts/Roboto-Regular.ttf",
+ "perf/texts/en-words.txt",
+ false},
+
+ {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
+ "perf/texts/en-thelittleprince.txt",
+ true},
+};
+
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+// https://en.cppreference.com/w/cpp/thread/condition_variable/wait
+static std::condition_variable cv;
+static std::mutex cv_m;
+static bool ready = false;
+
+static unsigned num_repetitions = 1;
+static unsigned num_threads = 3;
+
+static void shape (const test_input_t &input,
+ hb_font_t *font)
+{
+ // Wait till all threads are ready.
+ {
+ std::unique_lock<std::mutex> lk (cv_m);
+ cv.wait(lk, [] {return ready;});
+ }
+
+ const char *lang_str = strrchr (input.text_path, '/');
+ lang_str = lang_str ? lang_str + 1 : input.text_path;
+ hb_language_t language = hb_language_from_string (lang_str, -1);
+
+ hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
+ assert (text_blob);
+ unsigned orig_text_length;
+ const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
+
+ hb_buffer_t *buf = hb_buffer_create ();
+ hb_buffer_set_flags (buf, HB_BUFFER_FLAG_VERIFY);
+ for (unsigned i = 0; i < num_repetitions; i++)
+ {
+ unsigned text_length = orig_text_length;
+ const char *text = orig_text;
+
+ const char *end;
+ while ((end = (const char *) memchr (text, '\n', text_length)))
+ {
+ hb_buffer_clear_contents (buf);
+ hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
+ hb_buffer_guess_segment_properties (buf);
+ hb_buffer_set_language (buf, language);
+ hb_shape (font, buf, nullptr, 0);
+
+ unsigned skip = end - text + 1;
+ text_length -= skip;
+ text += skip;
+ }
+ }
+ hb_buffer_destroy (buf);
+
+ hb_blob_destroy (text_blob);
+}
+
+static void test_backend (backend_t backend,
+ const char *backend_name,
+ bool variable,
+ const test_input_t &test_input)
+{
+ char name[1024] = "shape";
+ const char *p;
+ strcat (name, "/");
+ p = strrchr (test_input.font_path, '/');
+ strcat (name, p ? p + 1 : test_input.font_path);
+ strcat (name, "/");
+ p = strrchr (test_input.text_path, '/');
+ strcat (name, p ? p + 1 : test_input.text_path);
+ strcat (name, variable ? "/var" : "");
+ strcat (name, "/");
+ strcat (name, backend_name);
+
+ printf ("Testing %s\n", name);
+
+ hb_font_t *font;
+ {
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+ assert (blob);
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ }
+
+ if (variable)
+ {
+ hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+ hb_font_set_variations (font, &wght, 1);
+ }
+
+ switch (backend)
+ {
+ case HARFBUZZ:
+ hb_ot_font_set_funcs (font);
+ break;
+
+ case FREETYPE:
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+ break;
+ }
+
+ std::vector<std::thread> threads;
+ for (unsigned i = 0; i < num_threads; i++)
+ threads.push_back (std::thread (shape, test_input, font));
+
+ {
+ std::unique_lock<std::mutex> lk (cv_m);
+ ready = true;
+ }
+ cv.notify_all();
+
+ for (unsigned i = 0; i < num_threads; i++)
+ threads[i].join ();
+
+ hb_font_destroy (font);
+}
+
+int main(int argc, char** argv)
+{
+ if (argc > 1)
+ num_threads = atoi (argv[1]);
+ if (argc > 2)
+ num_repetitions = atoi (argv[2]);
+
+ /* Dummy call to alleviate _guess_segment_properties thread safety-ness
+ * https://github.com/harfbuzz/harfbuzz/issues/1191 */
+ hb_language_get_default ();
+
+ if (argc > 4)
+ {
+ num_tests = (argc - 3) / 2;
+ tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ tests[i].is_variable = true;
+ tests[i].font_path = argv[3 + i * 2];
+ tests[i].text_path = argv[4 + i * 2];
+ }
+ }
+
+ printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ auto& test_input = tests[i];
+ for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+ {
+ bool is_var = (bool) variable;
+
+ test_backend (HARFBUZZ, "hb", is_var, test_input);
+#ifdef HAVE_FREETYPE
+ test_backend (FREETYPE, "ft", is_var, test_input);
+#endif
+ }
+ }
+
+ if (tests != default_tests)
+ free (tests);
+}
diff --git a/test/threads/hb-subset-threads.cc b/test/threads/hb-subset-threads.cc
new file mode 100644
index 000000000..9d86d8d51
--- /dev/null
+++ b/test/threads/hb-subset-threads.cc
@@ -0,0 +1,180 @@
+#include <cassert>
+#include <cstring>
+#include <thread>
+#include <condition_variable>
+#include <vector>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb-subset.h"
+
+enum operation_t
+{
+ subset_codepoints,
+ subset_glyphs
+};
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+ const char *font_path;
+ const unsigned max_subset_size;
+} default_tests[] =
+{
+ {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000},
+ {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000},
+ {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000},
+ {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000},
+ {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000},
+ {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000},
+ {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000},
+};
+
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+
+// https://en.cppreference.com/w/cpp/thread/condition_variable/wait
+static std::condition_variable cv;
+static std::mutex cv_m;
+static bool ready = false;
+
+static unsigned num_repetitions = 1;
+static unsigned num_threads = 3;
+
+static void AddCodepoints(const hb_set_t* codepoints_in_font,
+ unsigned subset_size,
+ hb_subset_input_t* input)
+{
+ auto *unicodes = hb_subset_input_unicode_set (input);
+ hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ for (unsigned i = 0; i < subset_size; i++) {
+ if (!hb_set_next (codepoints_in_font, &cp)) return;
+ hb_set_add (unicodes, cp);
+ }
+}
+
+static void AddGlyphs(unsigned num_glyphs_in_font,
+ unsigned subset_size,
+ hb_subset_input_t* input)
+{
+ auto *glyphs = hb_subset_input_glyph_set (input);
+ for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
+ hb_set_add (glyphs, i);
+ }
+}
+
+static void subset (operation_t operation,
+ const test_input_t &test_input,
+ hb_face_t *face)
+{
+ // Wait till all threads are ready.
+ {
+ std::unique_lock<std::mutex> lk (cv_m);
+ cv.wait(lk, [] {return ready;});
+ }
+
+ unsigned subset_size = test_input.max_subset_size;
+
+ hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+ assert (input);
+
+ switch (operation)
+ {
+ case subset_codepoints:
+ {
+ hb_set_t* all_codepoints = hb_set_create ();
+ hb_face_collect_unicodes (face, all_codepoints);
+ AddCodepoints(all_codepoints, subset_size, input);
+ hb_set_destroy (all_codepoints);
+ }
+ break;
+
+ case subset_glyphs:
+ {
+ unsigned num_glyphs = hb_face_get_glyph_count (face);
+ AddGlyphs(num_glyphs, subset_size, input);
+ }
+ break;
+ }
+
+ for (unsigned i = 0; i < num_repetitions; i++)
+ {
+ hb_face_t* subset = hb_subset_or_fail (face, input);
+ assert (subset);
+ hb_face_destroy (subset);
+ }
+
+ hb_subset_input_destroy (input);
+}
+
+static void test_operation (operation_t operation,
+ const char *operation_name,
+ const test_input_t &test_input)
+{
+ char name[1024] = "subset";
+ const char *p;
+ strcat (name, "/");
+ p = strrchr (test_input.font_path, '/');
+ strcat (name, p ? p + 1 : test_input.font_path);
+ strcat (name, "/");
+ strcat (name, operation_name);
+
+ printf ("Testing %s\n", name);
+
+ hb_face_t *face;
+ {
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+ assert (blob);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ }
+
+ std::vector<std::thread> threads;
+ for (unsigned i = 0; i < num_threads; i++)
+ threads.push_back (std::thread (subset, operation, test_input, face));
+
+ {
+ std::unique_lock<std::mutex> lk (cv_m);
+ ready = true;
+ }
+ cv.notify_all();
+
+ for (unsigned i = 0; i < num_threads; i++)
+ threads[i].join ();
+
+ hb_face_destroy (face);
+}
+
+int main(int argc, char** argv)
+{
+ if (argc > 1)
+ num_threads = atoi (argv[1]);
+ if (argc > 2)
+ num_repetitions = atoi (argv[2]);
+
+ if (argc > 4)
+ {
+ num_tests = argc - 3;
+ tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ tests[i].font_path = argv[3 + i];
+ }
+ }
+
+ printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
+ for (unsigned i = 0; i < num_tests; i++)
+ {
+ auto& test_input = tests[i];
+ test_operation (subset_codepoints, "codepoints", test_input);
+ test_operation (subset_glyphs, "glyphs", test_input);
+ }
+
+ if (tests != default_tests)
+ free (tests);
+}
diff --git a/test/threads/meson.build b/test/threads/meson.build
new file mode 100644
index 000000000..1848a1c6e
--- /dev/null
+++ b/test/threads/meson.build
@@ -0,0 +1,28 @@
+test('shape_threads', executable('hb-shape-threads', 'hb-shape-threads.cc',
+ dependencies: [
+ freetype_dep, thread_dep
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz],
+ install: false,
+ ),
+ workdir: meson.current_source_dir() / '..' / '..',
+ timeout: 300,
+ suite: ['threads', 'slow'],
+)
+
+
+test('subset_threads', executable('hb-subset-threads', 'hb-subset-threads.cc',
+ dependencies: [
+ thread_dep
+ ],
+ cpp_args: [],
+ include_directories: [incconfig, incsrc],
+ link_with: [libharfbuzz, libharfbuzz_subset],
+ install: false,
+ ),
+ workdir: meson.current_source_dir() / '..' / '..',
+ timeout: 300,
+ suite: ['threads', 'slow'],
+)
diff --git a/util/Makefile.sources b/util/Makefile.sources
index df3ad4a41..628de050e 100644
--- a/util/Makefile.sources
+++ b/util/Makefile.sources
@@ -4,6 +4,8 @@ HB_VIEW_sources = \
font-options.hh \
hb-view.cc \
helper-cairo-ansi.hh \
+ helper-cairo-ft.hh \
+ helper-cairo-user.hh \
helper-cairo.hh \
main-font-text.hh \
options.hh \
@@ -26,6 +28,7 @@ HB_SHAPE_sources = \
shape-consumer.hh \
shape-format.hh \
shape-options.hh \
+ shape-output.hh \
text-options.hh \
$(NULL)
diff --git a/util/ansi-print.hh b/util/ansi-print.hh
index d251e54ec..0715f4926 100644
--- a/util/ansi-print.hh
+++ b/util/ansi-print.hh
@@ -175,11 +175,11 @@ struct biimage_t
for (unsigned int i = 1; i < 8; i++)
if (freq[bg] < freq[i])
bg = i;
- fg = 0;
- for (unsigned int i = 1; i < 8; i++)
- if (i != bg && freq[fg] < freq[i])
+ fg = 8;
+ for (unsigned int i = 0; i < 8; i++)
+ if (i != bg && (fg == 8 || freq[fg] < freq[i]))
fg = i;
- if (fg == bg || freq[fg] == 0) {
+ if (freq[fg] == 0) {
fg = bg;
unicolor = true;
}
@@ -196,11 +196,11 @@ struct biimage_t
color_t bgc = color_t::from_ansi (bg);
color_t fgc = color_t::from_ansi (fg);
color_diff_t diff = fgc.diff (bgc);
- int dd = diff.dot (diff);
+ double dd = sqrt (diff.dot (diff));
for (unsigned int y = 0; y < height; y++)
for (unsigned int x = 0; x < width; x++) {
- int d = diff.dot (image (x, y).diff (bgc));
- (*this)(x, y) = d < 0 ? 0 : d > dd ? 255 : lround (d * 255. / dd);
+ double d = sqrt (diff.dot (image (x, y).diff (bgc)));
+ (*this)(x, y) = d <= 0 ? 0 : d >= dd ? 255 : lround (d / dd * 255.);
}
}
@@ -249,7 +249,7 @@ block_best (const biimage_t &bi, bool *inverse)
total_i += c_i;
}
- /* Make the sums cummulative */
+ /* Make the sums cumulative */
for (unsigned int i = 1; i < bi.height; i++) {
row_sum[i] += row_sum[i - 1];
row_sum_i[i] += row_sum_i[i - 1];
@@ -356,13 +356,13 @@ block_best (const biimage_t &bi, bool *inverse)
case 1: c = "▟"; inv = true; break;
case 2: c = "▙"; inv = true; break;
case 4: c = "▖"; inv = false; break;
+ case 6: c = "▞"; inv = false; break;
+ case 7: c = "▛"; inv = false; break;
case 8: c = "▗"; inv = false; break;
case 9: c = "▚"; inv = false; break;
- case 6: c = "▞"; inv = false; break;
- case 7: c = "▜"; inv = true; break;
- case 11: c = "▜"; inv = true; break;
- case 13: c = "▙"; inv = true; break;
- case 14: c = "▟"; inv = true; break;
+ case 11: c = "▜"; inv = false; break;
+ case 13: c = "▙"; inv = false; break;
+ case 14: c = "▟"; inv = false; break;
}
if (c) {
score = qs;
diff --git a/util/font-options.hh b/util/font-options.hh
index fa1cffa86..331efd7da 100644
--- a/util/font-options.hh
+++ b/util/font-options.hh
@@ -44,7 +44,9 @@ struct font_options_t : face_options_t
{
~font_options_t ()
{
+#ifndef HB_NO_VAR
free (variations);
+#endif
g_free (font_funcs);
hb_font_destroy (font);
}
@@ -53,11 +55,15 @@ struct font_options_t : face_options_t
void post_parse (GError **error);
+ hb_bool_t sub_font = false;
+#ifndef HB_NO_VAR
hb_variation_t *variations = nullptr;
unsigned int num_variations = 0;
+#endif
int x_ppem = 0;
int y_ppem = 0;
double ptem = 0.;
+ double slant = 0.;
unsigned int subpixel_bits = SUBPIXEL_BITS;
mutable double font_size_x = DEFAULT_FONT_SIZE;
mutable double font_size_y = DEFAULT_FONT_SIZE;
@@ -73,10 +79,10 @@ static struct supported_font_funcs_t {
void (*func) (hb_font_t *);
} supported_font_funcs[] =
{
+ {"ot", hb_ot_font_set_funcs},
#ifdef HAVE_FREETYPE
{"ft", hb_ft_font_set_funcs},
#endif
- {"ot", hb_ot_font_set_funcs},
};
@@ -94,11 +100,15 @@ font_options_t::post_parse (GError **error)
hb_font_set_ppem (font, x_ppem, y_ppem);
hb_font_set_ptem (font, ptem);
+ hb_font_set_synthetic_slant (font, slant);
+
int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
int scale_y = (int) scalbnf (font_size_y, subpixel_bits);
hb_font_set_scale (font, scale_x, scale_y);
+#ifndef HB_NO_VAR
hb_font_set_variations (font, variations, num_variations);
+#endif
void (*set_font_funcs) (hb_font_t *) = nullptr;
if (!font_funcs)
@@ -137,9 +147,18 @@ font_options_t::post_parse (GError **error)
#ifdef HAVE_FREETYPE
hb_ft_font_set_load_flags (font, ft_load_flags);
#endif
+
+ if (sub_font)
+ {
+ hb_font_t *old_font = font;
+ font = hb_font_create_sub_font (old_font);
+ hb_font_set_scale (old_font, scale_x * 2, scale_y * 2);
+ hb_font_destroy (old_font);
+ }
}
+#ifndef HB_NO_VAR
static gboolean
parse_variations (const char *name G_GNUC_UNUSED,
const char *arg,
@@ -161,7 +180,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
p = s;
do {
font_opts->num_variations++;
- p = strchr (p, ',');
+ p = strpbrk (p, ", ");
if (p)
p++;
} while (p);
@@ -174,7 +193,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
p = s;
font_opts->num_variations = 0;
while (p && *p) {
- char *end = strchr (p, ',');
+ char *end = strpbrk (p, ", ");
if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
font_opts->num_variations++;
p = end ? end + 1 : nullptr;
@@ -182,6 +201,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
return true;
}
+#endif
static gboolean
parse_font_size (const char *name G_GNUC_UNUSED,
@@ -265,7 +285,11 @@ font_options_t::add_options (option_parser_t *parser)
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
{"font-ptem", 0, 0,
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
+ {"font-slant", 0, 0,
+ G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
+ {"sub-font", 0, G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"},
{"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"},
{nullptr}
};
@@ -276,6 +300,7 @@ font_options_t::add_options (option_parser_t *parser)
this,
false /* We add below. */);
+#ifndef HB_NO_VAR
const gchar *variations_help = "Comma-separated list of font variations\n"
"\n"
" Variations are set globally. The format for specifying variation settings\n"
@@ -298,6 +323,7 @@ font_options_t::add_options (option_parser_t *parser)
"Variations options:",
"Options for font variations used",
this);
+#endif
}
#endif
diff --git a/util/hb-ot-shape-closure.cc b/util/hb-ot-shape-closure.cc
index 7321f93b6..3b6751c35 100644
--- a/util/hb-ot-shape-closure.cc
+++ b/util/hb-ot-shape-closure.cc
@@ -59,8 +59,8 @@ struct shape_closure_consumer_t
failed = false;
buffer = hb_buffer_create ();
}
- template <typename text_options_t>
- bool consume_line (text_options_t &text_opts)
+ template <typename text_options_type>
+ bool consume_line (text_options_type &text_opts)
{
unsigned int text_len;
const char *text;
@@ -107,7 +107,7 @@ struct shape_closure_consumer_t
protected:
shape_options_t shaper;
- hb_bool_t show_glyph_names = false;
+ hb_bool_t show_glyph_names = true;
hb_set_t *glyphs = nullptr;
hb_font_t *font = nullptr;
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index 13c277a2a..9eec5636a 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -28,140 +28,16 @@
#include "batch.hh"
#include "font-options.hh"
#include "main-font-text.hh"
-#include "output-options.hh"
#include "shape-consumer.hh"
-#include "shape-format.hh"
+#include "shape-output.hh"
#include "text-options.hh"
const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
const unsigned SUBPIXEL_BITS = 0;
-struct output_buffer_t : output_options_t<>
-{
- void add_options (option_parser_t *parser)
- {
- parser->set_summary ("Shape text with given font.");
- output_options_t::add_options (parser, hb_buffer_serialize_list_formats ());
- format.add_options (parser);
- }
-
- void init (hb_buffer_t *buffer, const font_options_t *font_opts)
- {
- gs = g_string_new (nullptr);
- line_no = 0;
- font = hb_font_reference (font_opts->font);
-
- if (!output_format)
- serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
- else
- serialize_format = hb_buffer_serialize_format_from_string (output_format, -1);
- /* An empty "output_format" parameter basically skips output generating.
- * Useful for benchmarking. */
- if ((!output_format || *output_format) &&
- !hb_buffer_serialize_format_to_string (serialize_format))
- {
- if (explicit_output_format)
- fail (false, "Unknown output format `%s'; supported formats are: %s",
- output_format,
- g_strjoinv ("/", const_cast<char**> (hb_buffer_serialize_list_formats ())));
- else
- /* Just default to TEXT if not explicitly requested and the
- * file extension is not recognized. */
- serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
- }
-
- unsigned int flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
- if (!format.show_glyph_names)
- flags |= HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
- if (!format.show_clusters)
- flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
- if (!format.show_positions)
- flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
- if (!format.show_advances)
- flags |= HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES;
- if (format.show_extents)
- flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
- if (format.show_flags)
- flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
- serialize_flags = (hb_buffer_serialize_flags_t) flags;
-
- if (format.trace)
- hb_buffer_set_message_func (buffer, message_func, this, nullptr);
- }
- void new_line () { line_no++; }
- void consume_text (hb_buffer_t *buffer,
- const char *text,
- unsigned int text_len,
- hb_bool_t utf8_clusters)
- {
- g_string_set_size (gs, 0);
- format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
- fprintf (out_fp, "%s", gs->str);
- }
- void error (const char *message)
- {
- g_string_set_size (gs, 0);
- format.serialize_message (line_no, "error", message, gs);
- fprintf (out_fp, "%s", gs->str);
- }
- void consume_glyphs (hb_buffer_t *buffer,
- const char *text,
- unsigned int text_len,
- hb_bool_t utf8_clusters)
- {
- g_string_set_size (gs, 0);
- format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
- serialize_format, serialize_flags, gs);
- fprintf (out_fp, "%s", gs->str);
- }
- void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
- {
- hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr);
- hb_font_destroy (font);
- g_string_free (gs, true);
- gs = nullptr;
- font = nullptr;
- }
-
- static hb_bool_t
- message_func (hb_buffer_t *buffer,
- hb_font_t *font,
- const char *message,
- void *user_data)
- {
- output_buffer_t *that = (output_buffer_t *) user_data;
- that->trace (buffer, font, message);
- return true;
- }
-
- void
- trace (hb_buffer_t *buffer,
- hb_font_t *font,
- const char *message)
- {
- g_string_set_size (gs, 0);
- format.serialize_line_no (line_no, gs);
- g_string_append_printf (gs, "trace: %s buffer: ", message);
- format.serialize (buffer, font, serialize_format, serialize_flags, gs);
- g_string_append_c (gs, '\n');
- fprintf (out_fp, "%s", gs->str);
- }
-
-
- protected:
-
- shape_format_options_t format;
-
- GString *gs = nullptr;
- unsigned int line_no = 0;
- hb_font_t *font = nullptr;
- hb_buffer_serialize_format_t serialize_format = HB_BUFFER_SERIALIZE_FORMAT_INVALID;
- hb_buffer_serialize_flags_t serialize_flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
-};
-
int
main (int argc, char **argv)
{
- using main_t = main_font_text_t<shape_consumer_t<output_buffer_t>, font_options_t, shape_text_options_t>;
+ using main_t = main_font_text_t<shape_consumer_t<shape_output_t>, font_options_t, shape_text_options_t>;
return batch_main<main_t> (argc, argv);
}
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index ec763309e..bd4dea2d3 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -32,6 +32,11 @@
#include <hb-subset.h>
+static hb_face_t* preprocess_face(hb_face_t* face)
+{
+ return hb_subset_preprocess (face);
+}
+
/*
* Command line interface to the harfbuzz font subsetter.
*/
@@ -103,11 +108,15 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
{
parse (argc, argv);
+ hb_face_t* orig_face = face;
+ if (preprocess)
+ orig_face = preprocess_face (face);
+
hb_face_t *new_face = nullptr;
for (unsigned i = 0; i < num_iterations; i++)
{
hb_face_destroy (new_face);
- new_face = hb_subset_or_fail (face, input);
+ new_face = hb_subset_or_fail (orig_face, input);
}
bool success = new_face;
@@ -119,6 +128,8 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
}
hb_face_destroy (new_face);
+ if (preprocess)
+ hb_face_destroy (orig_face);
return success ? 0 : 1;
}
@@ -160,6 +171,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
public:
unsigned num_iterations = 1;
+ gboolean preprocess;
hb_subset_input_t *input = nullptr;
};
@@ -532,30 +544,31 @@ set_flag (const char *name,
}
static gboolean
-parse_layout_features (const char *name,
- const char *arg,
- gpointer data,
- GError **error G_GNUC_UNUSED)
+parse_layout_tag_list (hb_subset_sets_t set_type,
+ const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error G_GNUC_UNUSED)
{
subset_main_t *subset_main = (subset_main_t *) data;
hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
hb_bool_t is_add = (name[strlen (name) - 1] == '+');
- hb_set_t *layout_features = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG);
+ hb_set_t *layout_tags = hb_subset_input_set (subset_main->input, set_type);
- if (!is_remove && !is_add) hb_set_clear (layout_features);
+ if (!is_remove && !is_add) hb_set_clear (layout_tags);
if (0 == strcmp (arg, "*"))
{
- hb_set_clear (layout_features);
+ hb_set_clear (layout_tags);
if (!is_remove)
- hb_set_invert (layout_features);
+ hb_set_invert (layout_tags);
return true;
}
char *s = strtok((char *) arg, ", ");
while (s)
{
- if (strlen (s) > 4) // table tags are at most 4 bytes
+ if (strlen (s) > 4) // tags are at most 4 bytes
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Failed parsing table tag at: '%s'", s);
@@ -565,9 +578,9 @@ parse_layout_features (const char *name,
hb_tag_t tag = hb_tag_from_string (s, strlen (s));
if (!is_remove)
- hb_set_add (layout_features, tag);
+ hb_set_add (layout_tags, tag);
else
- hb_set_del (layout_features, tag);
+ hb_set_del (layout_tags, tag);
s = strtok(nullptr, ", ");
}
@@ -576,6 +589,34 @@ parse_layout_features (const char *name,
}
static gboolean
+parse_layout_features (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+
+{
+ return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+ name,
+ arg,
+ data,
+ error);
+}
+
+static gboolean
+parse_layout_scripts (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+
+{
+ return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
+ name,
+ arg,
+ data,
+ error);
+}
+
+static gboolean
parse_drop_tables (const char *name,
const char *arg,
gpointer data,
@@ -619,6 +660,71 @@ parse_drop_tables (const char *name,
return true;
}
+#ifndef HB_NO_VAR
+static gboolean
+parse_instance (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ subset_main_t *subset_main = (subset_main_t *) data;
+
+ char *s = strtok((char *) arg, "=");
+ while (s)
+ {
+ unsigned len = strlen (s);
+ if (len > 4) //Axis tags are 4 bytes.
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Failed parsing axis tag at: '%s'", s);
+ return false;
+ }
+
+ hb_tag_t axis_tag = hb_tag_from_string (s, len);
+
+ s = strtok(nullptr, ", ");
+ if (!s)
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
+ return false;
+ }
+
+ if (strcmp (s, "drop") == 0)
+ {
+ if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag))
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+ return false;
+ }
+ }
+ else
+ {
+ errno = 0;
+ char *p;
+ float axis_value = strtof (s, &p);
+ if (errno || s == p)
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Failed parsing axis value at: '%s'", s);
+ return false;
+ }
+
+ if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value))
+ {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+ return false;
+ }
+ }
+ s = strtok(nullptr, "=");
+ }
+
+ return true;
+}
+#endif
+
template <GOptionArgFunc line_parser, bool allow_comments=true>
static gboolean
parse_file_for (const char *name,
@@ -728,7 +834,7 @@ subset_main_t::add_options ()
GOptionEntry glyphset_entries[] =
{
- {"gids", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
+ {"gids", 'g', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
"Specify glyph IDs or ranges to include in the subset.\n"
" "
"Use --gids-=... to subtract codepoints from the current set.", "list of glyph indices/ranges or *"},
@@ -740,15 +846,15 @@ subset_main_t::add_options ()
{"glyphs-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs, "Specify glyph names to remove from the subset", "list of glyph names"},
- {"glyphs-file", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>, "Specify file to read glyph names fromt", "filename"},
+ {"glyphs-file", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>, "Specify file to read glyph names from", "filename"},
- {"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
+ {"text", 't', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
{"text-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to remove from the subset", "string"},
{"text+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Specify text to include in the subset", "string"},
{"text-file", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_text, false>,"Specify file to read text from", "filename"},
- {"unicodes", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
+ {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
"Specify Unicode codepoints or ranges to include in the subset. Use * to include all codepoints.\n"
" "
"--unicodes-=... can be used to subtract codepoints from the current set.\n"
@@ -771,18 +877,33 @@ subset_main_t::add_options ()
GOptionEntry other_entries[] =
{
- {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids. Use --name-IDs-=... to substract from the current set.", "list of int numbers or *"},
+ {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids. Use --name-IDs-=... to subtract from the current set.", "list of int numbers or *"},
{"name-IDs-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers or *"},
{"name-IDs+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers or *"},
- {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs. Use --name-languages-=... to substract from the current set.", "list of int numbers or *"},
+ {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs. Use --name-languages-=... to subtract from the current set.", "list of int numbers or *"},
{"name-languages-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers or *"},
{"name-languages+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers or *"},
- {"layout-features", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved. Use --layout-features-=... to substract from the current set.", "list of string table tags or *"},
- {"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
- {"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
- {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables. Use --drop-tables-=... to substract from the current set.", "list of string table tags or *"},
+
+ {"layout-features", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved. Use --layout-features-=... to subtract from the current set.", "list of string table tags or *"},
+ {"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
+ {"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
+
+ {"layout-scripts", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved. Use --layout-scripts-=... to subtract from the current set.", "list of string table tags or *"},
+ {"layout-scripts+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved", "list of string tags or *"},
+ {"layout-scripts-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved", "list of string tags or *"},
+
+ {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables. Use --drop-tables-=... to subtract from the current set.", "list of string table tags or *"},
{"drop-tables+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
{"drop-tables-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
+#ifndef HB_NO_VAR
+ {"instance", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
+ "(Partially|Fully) Instantiate a variable font. A location consists of the tag of a variation axis, followed by '=', followed by a\n"
+ "number or the literal string 'drop'\n"
+ " "
+ "For example: --instance=\"wdth=100 wght=200\" or --instance=\"wdth=drop\"\n"
+ "Note: currently only fully instancing to the default location is supported\n",
+ "list of comma separated axis-locations"},
+#endif
{nullptr}
};
add_group (other_entries,
@@ -801,6 +922,9 @@ subset_main_t::add_options ()
{"notdef-outline", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>, "Keep the outline of \'.notdef\' glyph", nullptr},
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
+ {"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
+ {"preprocess-face", 0, 0, G_OPTION_ARG_NONE, &this->preprocess,
+ "If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
{nullptr}
};
add_group (flag_entries,
diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh
index 8c8a1eece..9708ee9e8 100644
--- a/util/helper-cairo-ansi.hh
+++ b/util/helper-cairo-ansi.hh
@@ -41,7 +41,7 @@
# define CELL_H (2 * CELL_W)
static void
-chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
+chafa_print_image_rgb24 (const void *data, int width, int height, int stride, int level)
{
ChafaTermInfo *term_info;
ChafaSymbolMap *symbol_map;
@@ -84,12 +84,15 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
symbol_map = chafa_symbol_map_new ();
chafa_symbol_map_add_by_tags (symbol_map,
(ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK
- | CHAFA_SYMBOL_TAG_SPACE));
+ | CHAFA_SYMBOL_TAG_SPACE
+ | (level >= 2 ? CHAFA_SYMBOL_TAG_WEDGE : 0)
+ | (level >= 3 ? CHAFA_SYMBOL_TAG_ALL : 0)
+ ));
config = chafa_canvas_config_new ();
chafa_canvas_config_set_canvas_mode (config, mode);
chafa_canvas_config_set_pixel_mode (config, pixel_mode);
- chafa_canvas_config_set_cell_geometry (config, 10, 20);
+ chafa_canvas_config_set_cell_geometry (config, CELL_W, CELL_H);
chafa_canvas_config_set_geometry (config, cols, rows);
chafa_canvas_config_set_symbol_map (config, symbol_map);
chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN);
@@ -164,6 +167,7 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface,
uint32_t bg_color = data ? * (uint32_t *) data : 0;
/* Drop first row while empty */
+ auto orig_data = data;
while (height)
{
unsigned int i;
@@ -175,9 +179,14 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface,
data += stride / 4;
height--;
}
+ if (orig_data < data)
+ {
+ data -= stride / 4;
+ height++; /* Add one first blank row for padding. */
+ }
/* Drop last row while empty */
- unsigned int orig_height = height;
+ auto orig_height = height;
while (height)
{
const uint32_t *row = data + (height - 1) * stride / 4;
@@ -195,8 +204,12 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface,
if (width && height)
{
#ifdef HAVE_CHAFA
- if (true)
- chafa_print_image_rgb24 (data, width, height, stride);
+ const char *env = getenv ("HB_CHAFA");
+ int chafa_level = 1;
+ if (env)
+ chafa_level = atoi (env);
+ if (chafa_level)
+ chafa_print_image_rgb24 (data, width, height, stride, chafa_level);
else
#endif
ansi_print_image_rgb24 (data, width, height, stride / 4);
diff --git a/util/helper-cairo-ft.hh b/util/helper-cairo-ft.hh
new file mode 100644
index 000000000..5152c7cac
--- /dev/null
+++ b/util/helper-cairo-ft.hh
@@ -0,0 +1,120 @@
+/*
+ * 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): Behdad Esfahbod
+ */
+
+#ifndef HELPER_CAIRO_FT_HH
+#define HELPER_CAIRO_FT_HH
+
+#include "font-options.hh"
+
+#include <cairo-ft.h>
+#include <hb-ft.h>
+#include FT_MULTIPLE_MASTERS_H
+
+static FT_Library ft_library;
+
+#ifdef HAVE_ATEXIT
+static inline
+void free_ft_library ()
+{
+ FT_Done_FreeType (ft_library);
+}
+#endif
+
+static inline cairo_font_face_t *
+helper_cairo_create_ft_font_face (const font_options_t *font_opts)
+{
+ cairo_font_face_t *cairo_face;
+ /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
+ * cairo will reset the face size. As such, create new face...
+ * TODO Perhaps add API to hb-ft to encapsulate this code. */
+ FT_Face ft_face = nullptr;//hb_ft_font_get_face (font);
+ if (!ft_face)
+ {
+ if (!ft_library)
+ {
+ FT_Init_FreeType (&ft_library);
+#ifdef HAVE_ATEXIT
+ atexit (free_ft_library);
+#endif
+ }
+
+ unsigned int blob_length;
+ const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
+
+ if (FT_New_Memory_Face (ft_library,
+ (const FT_Byte *) blob_data,
+ blob_length,
+ font_opts->face_index,
+ &ft_face))
+ fail (false, "FT_New_Memory_Face fail");
+ }
+ if (!ft_face)
+ {
+ /* This allows us to get some boxes at least... */
+ cairo_face = cairo_toy_font_face_create ("@cairo:sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ }
+ else
+ {
+#if !defined(HB_NO_VAR) && defined(HAVE_FT_SET_VAR_BLEND_COORDINATES)
+ unsigned int num_coords;
+ const float *coords = hb_font_get_var_coords_design (font_opts->font, &num_coords);
+ if (num_coords)
+ {
+ FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
+ if (ft_coords)
+ {
+ for (unsigned int i = 0; i < num_coords; i++)
+ ft_coords[i] = coords[i] * 65536.f;
+ FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
+ free (ft_coords);
+ }
+ }
+#endif
+
+ cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags);
+ }
+ return cairo_face;
+}
+
+static inline bool
+helper_cairo_ft_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
+{
+ bool ret = false;
+#ifdef FT_HAS_COLOR
+ FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+ if (ft_face)
+ {
+ if (FT_HAS_COLOR (ft_face))
+ ret = true;
+ cairo_ft_scaled_font_unlock_face (scaled_font);
+ }
+#endif
+ return ret;
+}
+
+#endif
diff --git a/util/helper-cairo-user.hh b/util/helper-cairo-user.hh
new file mode 100644
index 000000000..8c1f9f222
--- /dev/null
+++ b/util/helper-cairo-user.hh
@@ -0,0 +1,316 @@
+/*
+ * 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): Behdad Esfahbod
+ */
+
+#ifndef HELPER_CAIRO_USER_HH
+#define HELPER_CAIRO_USER_HH
+
+#include "font-options.hh"
+
+#include <cairo.h>
+#include <hb.h>
+
+#include "hb-blob.hh"
+
+static void
+move_to (hb_draw_funcs_t *dfuncs,
+ cairo_t *cr,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *)
+{
+ cairo_move_to (cr,
+ (double) to_x, (double) to_y);
+}
+
+static void
+line_to (hb_draw_funcs_t *dfuncs,
+ cairo_t *cr,
+ hb_draw_state_t *st,
+ float to_x, float to_y,
+ void *)
+{
+ cairo_line_to (cr,
+ (double) to_x, (double) to_y);
+}
+
+static void
+cubic_to (hb_draw_funcs_t *dfuncs,
+ cairo_t *cr,
+ hb_draw_state_t *st,
+ float control1_x, float control1_y,
+ float control2_x, float control2_y,
+ float to_x, float to_y,
+ void *)
+{
+ cairo_curve_to (cr,
+ (double) control1_x, (double) control1_y,
+ (double) control2_x, (double) control2_y,
+ (double) to_x, (double) to_y);
+}
+
+static void
+close_path (hb_draw_funcs_t *dfuncs,
+ cairo_t *cr,
+ hb_draw_state_t *st,
+ void *)
+{
+ cairo_close_path (cr);
+}
+
+
+static hb_draw_funcs_t *
+get_cairo_draw_funcs ()
+{
+ static hb_draw_funcs_t *funcs;
+
+ if (!funcs)
+ {
+ funcs = hb_draw_funcs_create ();
+ hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
+ hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
+ hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
+ hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
+ }
+
+ return funcs;
+}
+
+static const cairo_user_data_key_t _hb_font_cairo_user_data_key = {0};
+
+static cairo_status_t
+render_glyph (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *extents)
+{
+ hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &_hb_font_cairo_user_data_key));
+
+ hb_position_t x_scale, y_scale;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+ hb_font_get_glyph_shape (font, glyph, get_cairo_draw_funcs (), cr);
+ cairo_fill (cr);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+static inline cairo_status_t
+_hb_bytes_read_func (hb_bytes_t *src,
+ char *data,
+ unsigned length)
+{
+ if (unlikely (src->length < length))
+ return CAIRO_STATUS_READ_ERROR;
+
+ memcpy (data, src->arrayZ, length);
+ *src += length;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+render_color_glyph_png (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *extents)
+{
+ hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &_hb_font_cairo_user_data_key));
+
+ hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph);
+ if (blob == hb_blob_get_empty ())
+ return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+
+ hb_position_t x_scale, y_scale;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+ /* Draw PNG. */
+ hb_bytes_t bytes = blob->as_bytes ();
+ cairo_surface_t *surface = cairo_image_surface_create_from_png_stream ((cairo_read_func_t) _hb_bytes_read_func,
+ std::addressof (bytes));
+ hb_blob_destroy (blob);
+
+ if (unlikely (cairo_surface_status (surface)) != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (surface);
+ return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+ }
+
+ int width = cairo_image_surface_get_width (surface);
+ int height = cairo_image_surface_get_width (surface);
+
+ hb_glyph_extents_t hb_extents;
+ if (unlikely (!hb_font_get_glyph_extents (font, glyph, &hb_extents)))
+ {
+ cairo_surface_destroy (surface);
+ return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+ }
+
+ cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_translate (cr, hb_extents.x_bearing, hb_extents.y_bearing);
+ cairo_scale (cr, hb_extents.width, hb_extents.height);
+ cairo_set_source (cr, pattern);
+
+ cairo_rectangle (cr, 0, 0, 1, 1);
+ cairo_fill (cr);
+ cairo_pattern_destroy (pattern);
+
+ cairo_surface_destroy (surface);
+ return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
+static cairo_status_t
+render_color_glyph_layers (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *extents)
+{
+ hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &_hb_font_cairo_user_data_key));
+ hb_face_t *face = hb_font_get_face (font);
+
+ unsigned count = hb_ot_color_glyph_get_layers (face, glyph, 0, nullptr, nullptr);
+ if (!count)
+ return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+
+ hb_ot_color_layer_t layers[16];
+ unsigned offset = 0, len;
+ do {
+ len = ARRAY_LENGTH (layers);
+ hb_ot_color_glyph_get_layers (face, glyph,
+ offset,
+ &len,
+ layers);
+ for (unsigned i = 0; i < len; i++)
+ {
+ hb_color_t color;
+ unsigned clen = 1;
+ unsigned color_index = layers[i].color_index;
+ bool is_foreground = color_index == 65535;
+
+ if (!is_foreground)
+ {
+ hb_ot_color_palette_get_colors (face,
+ 0/*palette_index*/,
+ color_index/*start_offset*/,
+ &clen/*color_count*/,
+ &color);
+ if (clen < 1)
+ continue;
+ }
+
+ cairo_save (cr);
+ {
+ if (!is_foreground)
+ cairo_set_source_rgba (cr,
+ hb_color_get_red (color) / 255.,
+ hb_color_get_green (color) / 255.,
+ hb_color_get_blue (color) / 255.,
+ hb_color_get_alpha (color) / 255.);
+
+ cairo_status_t ret = render_glyph (scaled_font, layers[i].glyph, cr, extents);
+ if (ret != CAIRO_STATUS_SUCCESS)
+ return ret;
+ }
+ cairo_restore (cr);
+ }
+ }
+ while (len == ARRAY_LENGTH (layers));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+render_color_glyph (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *extents)
+{
+ cairo_status_t ret = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ ret = render_color_glyph_png (scaled_font, glyph, cr, extents);
+ if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
+ return ret;
+#endif
+
+ ret = render_color_glyph_layers (scaled_font, glyph, cr, extents);
+ if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
+ return ret;
+
+ return render_glyph (scaled_font, glyph, cr, extents);
+}
+
+#endif
+
+static inline cairo_font_face_t *
+helper_cairo_create_user_font_face (const font_options_t *font_opts)
+{
+ cairo_font_face_t *cairo_face = cairo_user_font_face_create ();
+
+ cairo_font_face_set_user_data (cairo_face,
+ &_hb_font_cairo_user_data_key,
+ hb_font_reference (font_opts->font),
+ (cairo_destroy_func_t) hb_font_destroy);
+
+ cairo_user_font_face_set_render_glyph_func (cairo_face, render_glyph);
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+ hb_face_t *face = hb_font_get_face (font_opts->font);
+ if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face))
+ cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_color_glyph);
+#endif
+
+ return cairo_face;
+}
+
+static inline bool
+helper_cairo_user_font_face_has_data (cairo_font_face_t *font_face)
+{
+ return cairo_font_face_get_user_data (font_face, &_hb_font_cairo_user_data_key);
+}
+
+static inline bool
+helper_cairo_user_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
+{
+ /* Ignoring SVG for now, since we cannot render it. */
+ hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &_hb_font_cairo_user_data_key));
+ hb_face_t *face = hb_font_get_face (font);
+ return hb_ot_color_has_png (face) || hb_ot_color_has_layers (face);
+}
+
+#endif
diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh
index b8d461224..a8463de4d 100644
--- a/util/helper-cairo.hh
+++ b/util/helper-cairo.hh
@@ -29,10 +29,13 @@
#include "view-options.hh"
#include "output-options.hh"
+#ifdef HAVE_CAIRO_FT
+# include "helper-cairo-ft.hh"
+#endif
+#include "helper-cairo-user.hh"
-#include <cairo-ft.h>
-#include <hb-ft.h>
-#include FT_MULTIPLE_MASTERS_H
+#include <cairo.h>
+#include <hb.h>
#include "helper-cairo-ansi.hh"
#ifdef CAIRO_HAS_SVG_SURFACE
@@ -65,74 +68,41 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t write_func,
# endif
#endif
-
-static FT_Library ft_library;
-
-#ifdef HAVE_ATEXIT
-static inline
-void free_ft_library ()
+static inline bool
+helper_cairo_use_hb_draw (const font_options_t *font_opts)
{
- FT_Done_FreeType (ft_library);
-}
+ const char *env = getenv ("HB_DRAW");
+ if (!env)
+#if 1
+ /* Following branch disabled because we prefer our
+ * OpenType extensions working, ie going through hb-draw,
+ * over avoiding the obscure cairo bug. */
+ return true;
+#else
+ /* Older cairo had a bug in rendering COLRv0 fonts in
+ * right-to-left direction. */
+ return cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 5);
#endif
+ return atoi (env);
+}
+
static inline cairo_scaled_font_t *
helper_cairo_create_scaled_font (const font_options_t *font_opts)
{
hb_font_t *font = hb_font_reference (font_opts->font);
+#ifdef HAVE_CAIRO_FT
+ bool use_hb_draw = helper_cairo_use_hb_draw (font_opts);
cairo_font_face_t *cairo_face;
- /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
- * cairo will reset the face size. As such, create new face...
- * TODO Perhaps add API to hb-ft to encapsulate this code. */
- FT_Face ft_face = nullptr;//hb_ft_font_get_face (font);
- if (!ft_face)
- {
- if (!ft_library)
- {
- FT_Init_FreeType (&ft_library);
-#ifdef HAVE_ATEXIT
- atexit (free_ft_library);
-#endif
- }
-
- unsigned int blob_length;
- const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
-
- if (FT_New_Memory_Face (ft_library,
- (const FT_Byte *) blob_data,
- blob_length,
- font_opts->face_index,
- &ft_face))
- fail (false, "FT_New_Memory_Face fail");
- }
- if (!ft_face)
- {
- /* This allows us to get some boxes at least... */
- cairo_face = cairo_toy_font_face_create ("@cairo:sans",
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_NORMAL);
- }
+ if (use_hb_draw)
+ cairo_face = helper_cairo_create_user_font_face (font_opts);
else
- {
-#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
- 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 *) calloc (num_coords, sizeof (FT_Fixed));
- if (ft_coords)
- {
- for (unsigned int i = 0; i < num_coords; i++)
- ft_coords[i] = coords[i] << 2;
- FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
- free (ft_coords);
- }
- }
+ cairo_face = helper_cairo_create_ft_font_face (font_opts);
+#else
+ cairo_font_face_t *cairo_face = helper_cairo_create_user_font_face (font_opts);
#endif
- cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags);
- }
cairo_matrix_t ctm, font_matrix;
cairo_font_options_t *font_options;
@@ -140,6 +110,11 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
cairo_matrix_init_scale (&font_matrix,
font_opts->font_size_x,
font_opts->font_size_y);
+#ifdef HAVE_CAIRO_FT
+ if (!use_hb_draw)
+ font_matrix.xy = -font_opts->slant * font_opts->font_size_x;
+#endif
+
font_options = cairo_font_options_create ();
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
@@ -165,17 +140,14 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
static inline bool
helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
{
- bool ret = false;
-#ifdef FT_HAS_COLOR
- FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
- if (ft_face)
- {
- if (FT_HAS_COLOR (ft_face))
- ret = true;
- cairo_ft_scaled_font_unlock_face (scaled_font);
- }
+#ifdef HAVE_CAIRO_FT
+ if (helper_cairo_user_font_face_has_data (cairo_scaled_font_get_font_face (scaled_font)))
+ return helper_cairo_user_scaled_font_has_color (scaled_font);
+ else
+ return helper_cairo_ft_scaled_font_has_color (scaled_font);
+#else
+ return helper_cairo_user_scaled_font_has_color (scaled_font);
#endif
- return ret;
}
@@ -427,11 +399,11 @@ static const char *helper_cairo_supported_formats[] =
};
template <typename view_options_t,
- typename output_options_t>
+ typename output_options_type>
static inline cairo_t *
helper_cairo_create_context (double w, double h,
view_options_t *view_opts,
- output_options_t *out_opts,
+ output_options_type *out_opts,
cairo_content_t content)
{
cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
@@ -460,6 +432,12 @@ helper_cairo_create_context (double w, double h,
extension = "png";
protocol = image_protocol_t::ITERM2;
}
+ else if ((name = getenv ("TERM_PROGRAM")) != nullptr &&
+ 0 == g_ascii_strcasecmp (name, "WezTerm"))
+ {
+ extension = "png";
+ protocol = image_protocol_t::ITERM2;
+ }
else if ((name = getenv ("TERM")) != nullptr &&
0 == g_ascii_strcasecmp (name, "xterm-kitty"))
{
diff --git a/util/main-font-text.hh b/util/main-font-text.hh
index dabbd3285..ca39c5a47 100644
--- a/util/main-font-text.hh
+++ b/util/main-font-text.hh
@@ -31,8 +31,14 @@
/* main() body for utilities taking font and processing text.*/
-template <typename consumer_t, typename font_options_t, typename text_options_t>
-struct main_font_text_t : option_parser_t, font_options_t, text_options_t, consumer_t
+template <typename consumer_t,
+ typename font_options_type,
+ typename text_options_type>
+struct main_font_text_t :
+ option_parser_t,
+ font_options_type,
+ text_options_type,
+ consumer_t
{
int operator () (int argc, char **argv)
{
@@ -53,8 +59,8 @@ struct main_font_text_t : option_parser_t, font_options_t, text_options_t, consu
void add_options ()
{
- font_options_t::add_options (this);
- text_options_t::add_options (this);
+ font_options_type::add_options (this);
+ text_options_type::add_options (this);
consumer_t::add_options (this);
GOptionEntry entries[] =
diff --git a/util/meson.build b/util/meson.build
index fdab620fc..136740554 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -17,8 +17,7 @@ hb_subset_cli_sources = [
util_deps = [freetype_dep, cairo_dep, cairo_ft_dep, glib_dep]
if conf.get('HAVE_GLIB', 0) == 1
- if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_CAIRO_FT', 0) == 1
-
+ if conf.get('HAVE_CAIRO', 0) == 1
hb_view = executable('hb-view', hb_view_sources,
cpp_args: cpp_args,
include_directories: [incconfig, incsrc],
diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh
index 21151890b..8ee4bd697 100644
--- a/util/shape-consumer.hh
+++ b/util/shape-consumer.hh
@@ -61,11 +61,11 @@ struct shape_consumer_t : shape_options_t
for (unsigned int n = num_iterations; n; n--)
{
- const char *error = nullptr;
-
populate_buffer (buffer, text, text_len, app.text_before, app.text_after);
if (n == 1)
output.consume_text (buffer, text, text_len, utf8_clusters);
+
+ const char *error = nullptr;
if (!shape (app.font, buffer, &error))
{
failed = true;
diff --git a/util/shape-options.hh b/util/shape-options.hh
index 8d3318420..e24f4f8e0 100644
--- a/util/shape-options.hh
+++ b/util/shape-options.hh
@@ -51,6 +51,9 @@ struct shape_options_t
(HB_BUFFER_FLAG_DEFAULT |
(bot ? HB_BUFFER_FLAG_BOT : 0) |
(eot ? HB_BUFFER_FLAG_EOT : 0) |
+ (verify ? HB_BUFFER_FLAG_VERIFY : 0) |
+ (unsafe_to_concat ? HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT : 0) |
+ (safe_to_insert_tatweel ? HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL : 0) |
(preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
(remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
0));
@@ -60,15 +63,6 @@ struct shape_options_t
hb_buffer_guess_segment_properties (buffer);
}
- static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src)
- {
- hb_segment_properties_t props;
- hb_buffer_get_segment_properties (src, &props);
- hb_buffer_set_segment_properties (dst, &props);
- hb_buffer_set_flags (dst, hb_buffer_get_flags (src));
- hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src));
- }
-
void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
const char *text_before, const char *text_after)
{
@@ -99,187 +93,22 @@ struct shape_options_t
hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
{
- hb_buffer_t *text_buffer = nullptr;
- if (verify)
- {
- text_buffer = hb_buffer_create ();
- hb_buffer_append (text_buffer, buffer, 0, -1);
- }
-
if (!hb_shape_full (font, buffer, features, num_features, shapers))
{
if (error)
- *error = "All shapers failed.";
+ *error = "Shaping failed.";
goto fail;
}
if (normalize_glyphs)
hb_buffer_normalize_glyphs (buffer);
- if (verify && !verify_buffer (buffer, text_buffer, font, error))
- goto fail;
-
- if (text_buffer)
- hb_buffer_destroy (text_buffer);
-
return true;
fail:
- if (text_buffer)
- hb_buffer_destroy (text_buffer);
-
return false;
}
- bool verify_buffer (hb_buffer_t *buffer,
- hb_buffer_t *text_buffer,
- hb_font_t *font,
- const char **error=nullptr)
- {
- if (!verify_buffer_monotone (buffer, error))
- return false;
- if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error))
- return false;
- return true;
- }
-
- bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr)
- {
- /* Check that clusters are monotone. */
- if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
- cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- {
- bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
-
- unsigned int num_glyphs;
- hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
-
- for (unsigned int i = 1; i < num_glyphs; i++)
- if (info[i-1].cluster != info[i].cluster &&
- (info[i-1].cluster < info[i].cluster) != is_forward)
- {
- if (error)
- *error = "clusters are not monotone.";
- return false;
- }
- }
-
- return true;
- }
-
- bool verify_buffer_safe_to_break (hb_buffer_t *buffer,
- hb_buffer_t *text_buffer,
- hb_font_t *font,
- const char **error=nullptr)
- {
- if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
- cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- {
- /* Cannot perform this check without monotone clusters.
- * Then again, unsafe-to-break flag is much harder to use without
- * monotone clusters. */
- return true;
- }
-
- /* Check that breaking up shaping at safe-to-break is indeed safe. */
-
- hb_buffer_t *fragment = hb_buffer_create ();
- hb_buffer_t *reconstruction = hb_buffer_create ();
- copy_buffer_properties (reconstruction, buffer);
-
- unsigned int num_glyphs;
- hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
-
- unsigned int num_chars;
- hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
-
- /* Chop text and shape fragments. */
- bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
- unsigned int start = 0;
- unsigned int text_start = forward ? 0 : num_chars;
- unsigned int text_end = text_start;
- for (unsigned int end = 1; end < num_glyphs + 1; end++)
- {
- if (end < num_glyphs &&
- (info[end].cluster == info[end-1].cluster ||
- info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
- continue;
-
- /* Shape segment corresponding to glyphs start..end. */
- if (end == num_glyphs)
- {
- if (forward)
- text_end = num_chars;
- else
- text_start = 0;
- }
- else
- {
- if (forward)
- {
- unsigned int cluster = info[end].cluster;
- while (text_end < num_chars && text[text_end].cluster < cluster)
- text_end++;
- }
- else
- {
- unsigned int cluster = info[end - 1].cluster;
- while (text_start && text[text_start - 1].cluster >= cluster)
- text_start--;
- }
- }
- assert (text_start < text_end);
-
- if (0)
- printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
-
- hb_buffer_clear_contents (fragment);
- copy_buffer_properties (fragment, buffer);
-
- hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
- if (0 < text_start)
- flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
- if (text_end < num_chars)
- flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
- hb_buffer_set_flags (fragment, flags);
-
- hb_buffer_append (fragment, text_buffer, text_start, text_end);
- if (!hb_shape_full (font, fragment, features, num_features, shapers))
- {
- if (error)
- *error = "All shapers failed while shaping fragment.";
- hb_buffer_destroy (reconstruction);
- hb_buffer_destroy (fragment);
- return false;
- }
- hb_buffer_append (reconstruction, fragment, 0, -1);
-
- start = end;
- if (forward)
- text_start = text_end;
- else
- text_end = text_start;
- }
-
- bool ret = true;
- hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff)
- {
- if (error)
- *error = "Safe-to-break test failed.";
- ret = false;
-
- /* Return the reconstructed result instead so it can be inspected. */
- hb_buffer_set_length (buffer, 0);
- hb_buffer_append (buffer, reconstruction, 0, -1);
- }
-
- hb_buffer_destroy (reconstruction);
- hb_buffer_destroy (fragment);
-
- return ret;
- }
-
void shape_closure (const char *text, int text_len,
hb_font_t *font, hb_buffer_t *buffer,
hb_set_t *glyphs)
@@ -310,6 +139,8 @@ struct shape_options_t
hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
hb_bool_t normalize_glyphs = false;
hb_bool_t verify = false;
+ hb_bool_t unsafe_to_concat = false;
+ hb_bool_t safe_to_insert_tatweel = false;
unsigned int num_iterations = 1;
};
@@ -389,7 +220,7 @@ parse_features (const char *name G_GNUC_UNUSED,
p = s;
do {
shape_opts->num_features++;
- p = strchr (p, ',');
+ p = strpbrk (p, ", ");
if (p)
p++;
} while (p);
@@ -402,7 +233,7 @@ parse_features (const char *name G_GNUC_UNUSED,
p = s;
shape_opts->num_features = 0;
while (p && *p) {
- char *end = strchr (p, ',');
+ char *end = strpbrk (p, ", ");
if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
shape_opts->num_features++;
p = end ? end + 1 : nullptr;
@@ -433,6 +264,8 @@ shape_options_t::add_options (option_parser_t *parser)
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr},
{"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"},
{"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr},
+ {"unsafe-to-concat",0, 0, G_OPTION_ARG_NONE, &this->unsafe_to_concat, "Produce unsafe-to-concat glyph flag", nullptr},
+ {"safe-to-insert-tatweel",0, 0, G_OPTION_ARG_NONE, &this->safe_to_insert_tatweel, "Produce safe-to-insert-tatweel glyph flag", nullptr},
{"verify", 0, 0, G_OPTION_ARG_NONE, &this->verify, "Perform sanity checks on shaping results", nullptr},
{"num-iterations", 'n', G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"},
diff --git a/util/shape-output.hh b/util/shape-output.hh
new file mode 100644
index 000000000..8d2080508
--- /dev/null
+++ b/util/shape-output.hh
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2010 Behdad Esfahbod
+ * 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_SHAPE_OUTPUT_HH
+#define HB_SHAPE_OUTPUT_HH
+
+#include "shape-format.hh"
+#include "output-options.hh"
+
+
+struct shape_output_t : output_options_t<>
+{
+ void add_options (option_parser_t *parser)
+ {
+ parser->set_summary ("Shape text with given font.");
+ output_options_t::add_options (parser, hb_buffer_serialize_list_formats ());
+ format.add_options (parser);
+ }
+
+ void init (hb_buffer_t *buffer, const font_options_t *font_opts)
+ {
+ gs = g_string_new (nullptr);
+ line_no = 0;
+ font = hb_font_reference (font_opts->font);
+
+ if (!output_format)
+ serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+ else
+ serialize_format = hb_buffer_serialize_format_from_string (output_format, -1);
+ /* An empty "output_format" parameter basically skips output generating.
+ * Useful for benchmarking. */
+ if ((!output_format || *output_format) &&
+ !hb_buffer_serialize_format_to_string (serialize_format))
+ {
+ if (explicit_output_format)
+ fail (false, "Unknown output format `%s'; supported formats are: %s",
+ output_format,
+ g_strjoinv ("/", const_cast<char**> (hb_buffer_serialize_list_formats ())));
+ else
+ /* Just default to TEXT if not explicitly requested and the
+ * file extension is not recognized. */
+ serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+ }
+
+ unsigned int flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
+ if (!format.show_glyph_names)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
+ if (!format.show_clusters)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
+ if (!format.show_positions)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+ if (!format.show_advances)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES;
+ if (format.show_extents)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
+ if (format.show_flags)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
+ serialize_flags = (hb_buffer_serialize_flags_t) flags;
+
+ if (format.trace)
+ hb_buffer_set_message_func (buffer, message_func, this, nullptr);
+ }
+ void new_line () { line_no++; }
+ void consume_text (hb_buffer_t *buffer,
+ const char *text,
+ unsigned int text_len,
+ hb_bool_t utf8_clusters)
+ {
+ g_string_set_size (gs, 0);
+ format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
+ fprintf (out_fp, "%s", gs->str);
+ }
+ void error (const char *message)
+ {
+ g_string_set_size (gs, 0);
+ format.serialize_message (line_no, "error", message, gs);
+ fprintf (out_fp, "%s", gs->str);
+ }
+ void consume_glyphs (hb_buffer_t *buffer,
+ const char *text,
+ unsigned int text_len,
+ hb_bool_t utf8_clusters)
+ {
+ g_string_set_size (gs, 0);
+ format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
+ serialize_format, serialize_flags, gs);
+ fprintf (out_fp, "%s", gs->str);
+ }
+ void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
+ {
+ hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr);
+ hb_font_destroy (font);
+ g_string_free (gs, true);
+ gs = nullptr;
+ font = nullptr;
+ }
+
+ static hb_bool_t
+ message_func (hb_buffer_t *buffer,
+ hb_font_t *font,
+ const char *message,
+ void *user_data)
+ {
+ shape_output_t *that = (shape_output_t *) user_data;
+ that->trace (buffer, font, message);
+ return true;
+ }
+
+ void
+ trace (hb_buffer_t *buffer,
+ hb_font_t *font,
+ const char *message)
+ {
+ g_string_set_size (gs, 0);
+ format.serialize_line_no (line_no, gs);
+ g_string_append_printf (gs, "trace: %s buffer: ", message);
+ format.serialize (buffer, font, serialize_format, serialize_flags, gs);
+ g_string_append_c (gs, '\n');
+ fprintf (out_fp, "%s", gs->str);
+ }
+
+
+ protected:
+
+ shape_format_options_t format;
+
+ GString *gs = nullptr;
+ unsigned int line_no = 0;
+ hb_font_t *font = nullptr;
+ hb_buffer_serialize_format_t serialize_format = HB_BUFFER_SERIALIZE_FORMAT_INVALID;
+ hb_buffer_serialize_flags_t serialize_flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
+};
+
+
+#endif
diff --git a/util/text-options.hh b/util/text-options.hh
index 82ca6c0bd..3043efc40 100644
--- a/util/text-options.hh
+++ b/util/text-options.hh
@@ -82,6 +82,9 @@ struct text_options_t
private:
FILE *in_fp = nullptr;
GString *gs = nullptr;
+ char *line = nullptr;
+ unsigned line_len = UINT_MAX;
+ hb_bool_t single_par = false;
};
struct shape_text_options_t : text_options_t
@@ -124,7 +127,7 @@ encode_unicodes (const char *unicodes,
GString *gs,
GError **error)
{
-#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r "
+#define DELIMITERS "<+-|>{},;&#\\xXuUnNiI\n\t\v\f\r "
char *s = (char *) unicodes;
char *p;
@@ -273,18 +276,38 @@ text_options_t::get_line (unsigned int *len)
{
if (text)
{
- if (text_len == -2)
+ if (!line)
+ {
+ line = text;
+ line_len = text_len;
+ }
+ if (line_len == UINT_MAX)
+ line_len = strlen (line);
+
+ if (!line_len)
{
*len = 0;
return nullptr;
}
- if (text_len == -1)
- text_len = strlen (text);
+ const char *ret = line;
+ const char *p = single_par ? nullptr : (const char *) memchr (line, '\n', line_len);
+ unsigned int ret_len;
+ if (!p)
+ {
+ ret_len = line_len;
+ line += ret_len;
+ line_len = 0;
+ }
+ else
+ {
+ ret_len = p - ret;
+ line += ret_len + 1;
+ line_len -= ret_len + 1;
+ }
- *len = text_len;
- text_len = -2;
- return text;
+ *len = ret_len;
+ return ret;
}
g_string_set_size (gs, 0);
@@ -292,7 +315,7 @@ text_options_t::get_line (unsigned int *len)
while (fgets (buf, sizeof (buf), in_fp))
{
unsigned bytes = strlen (buf);
- if (bytes && buf[bytes - 1] == '\n')
+ if (!single_par && bytes && buf[bytes - 1] == '\n')
{
bytes--;
g_string_append_len (gs, buf, bytes);
@@ -313,12 +336,13 @@ text_options_t::add_options (option_parser_t *parser)
{
{"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Set input text", "string"},
{"text-file", 0, 0, G_OPTION_ARG_STRING, &this->text_file, "Set input text file-name", "filename"},
- {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Set input Unicode codepoints\n\n If no text is provided, standard input is used for input.", "list of hex numbers"},
+ {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Set input Unicode codepoints", "list of hex numbers"},
+ {"single-par", 0, 0, G_OPTION_ARG_NONE, &this->single_par, "Treat text as single paragraph", nullptr},
{nullptr}
};
parser->add_group (entries,
"text",
- "Text options:",
+ "Text options:\n\nIf no text is provided, standard input is used for input.\n",
"Options for the input text",
this);
}